既然已经可以通过 RTSP 获取h264 裸流了。那么通过 FFmpeg 将其保存到文件中怎么做呢?

一、首先RTSP获取 h264 裸流

我们上面两篇文章主要讲的是通过 rtsp://Your ip:554/stream_chn0.h265 播放H.265视频流。

PS:我刚试了一下,我的 FFmpeg 程序暂时不支持 h265 ...   之前编译的时候,只提供了 x264没有x265

如果感兴趣参看下面两篇文章添加。

参看:使用VS2015添加对ffmpeg添加h265 支持。

参看:ffmpeg 编码H265和H264对比

再结合之前讲的,FFmepg 再学习系列,应该是没问题的。不过好久没有弄了,早忘了了。

那现在没有可以播放的 H.264 视频流了啊,怎么办?

有办法之前讲过一篇文章,参看:LIVE555再学习 -- VLC搭建RTSP服务器(转) 用VLC搭建一个不就完了。

当然还可以直接用 live555,参看:LIVE555再学习 -- live555实现RTSP直播服务器  (推荐)

二、FFmpeg 将H.264 裸流保存到文件

这个也好说,之前有讲到,参看:FFmpeg再学习 -- SDL 环境搭建和视频显示

将其改改就可以了。

具体代码如下:

参看:利用ffmpeg将RTSP传输的h264原始码流保存到文件中

  1. #include "stdafx.h"
  2. #include <stdio.h>
  3. #define __STDC_CONSTANT_MACROS
  4. #ifdef _WIN32
  5. //Windows
  6. extern "C"
  7. {
  8. #include "libavcodec/avcodec.h"
  9. #include "libavformat/avformat.h"
  10. #include "libswscale/swscale.h"
  11. #include "SDL2/SDL.h"
  12. };
  13. #else
  14. //Linux...
  15. #ifdef __cplusplus
  16. extern "C"
  17. {
  18. #endif
  19. #include <libavcodec/avcodec.h>
  20. #include <libavformat/avformat.h>
  21. #include <libswscale/swscale.h>
  22. #include <SDL2/SDL.h>
  23. #ifdef __cplusplus
  24. };
  25. #endif
  26. #endif
  27. int main(int argc, char* argv[])
  28. {
  29. AVFormatContext *pFormatCtx;
  30. int             i, videoindex;
  31. AVCodecContext  *pCodecCtx;
  32. AVCodec         *pCodec;
  33. AVFrame *pFrame, *pFrameYUV;
  34. uint8_t *out_buffer;
  35. AVPacket *packet;
  36. int ret, got_picture;
  37. struct SwsContext *img_convert_ctx;
  38. // 改成你自己的 URL
  39. char filepath[] = "rtsp://192.168.2.xx:8554/1";
  40. av_register_all();
  41. avformat_network_init();
  42. pFormatCtx = avformat_alloc_context();
  43. if (avformat_open_input(&pFormatCtx, filepath, NULL, NULL) != 0)////打开网络流或文件流
  44. {
  45. printf("Couldn't open input stream.\n");
  46. return -1;
  47. }
  48. if (avformat_find_stream_info(pFormatCtx, NULL)<0)
  49. {
  50. printf("Couldn't find stream information.\n");
  51. return -1;
  52. }
  53. videoindex = -1;
  54. for (i = 0; i<pFormatCtx->nb_streams; i++)
  55. if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
  56. {
  57. videoindex = i;
  58. break;
  59. }
  60. if (videoindex == -1)
  61. {
  62. printf("Didn't find a video stream.\n");
  63. return -1;
  64. }
  65. pCodecCtx = pFormatCtx->streams[videoindex]->codec;
  66. pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
  67. if (pCodec == NULL)
  68. {
  69. printf("Codec not found.\n");
  70. return -1;
  71. }
  72. if (avcodec_open2(pCodecCtx, pCodec, NULL)<0)
  73. {
  74. printf("Could not open codec.\n");
  75. return -1;
  76. }
  77. pFrame = av_frame_alloc();
  78. pFrameYUV = av_frame_alloc();
  79. out_buffer = (uint8_t *)av_malloc(avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));
  80. avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);
  81. //Output Info---输出一些文件(RTSP)信息
  82. printf("---------------- File Information ---------------\n");
  83. av_dump_format(pFormatCtx, 0, filepath, 0);
  84. printf("-------------------------------------------------\n");
  85. img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
  86. pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
  87. packet = (AVPacket *)av_malloc(sizeof(AVPacket));
  88. FILE *fpSave;
  89. if ((fpSave = fopen("geth264.h264", "ab")) == NULL) //h264保存的文件名
  90. return 0;
  91. for (;;)
  92. {
  93. //------------------------------
  94. if (av_read_frame(pFormatCtx, packet) >= 0)
  95. {
  96. if (packet->stream_index == videoindex)
  97. {
  98. fwrite(packet->data, 1, packet->size, fpSave);//写数据到文件中
  99. }
  100. av_free_packet(packet);
  101. }
  102. }
  103. //--------------
  104. av_frame_free(&pFrameYUV);
  105. av_frame_free(&pFrame);
  106. avcodec_close(pCodecCtx);
  107. avformat_close_input(&pFormatCtx);
  108. return 0;
  109. }

调试结果显示如下:

生成 geth264.h264 文件,可播放。

三、工程下载

下载:利用FFmpeg 将 rtsp 获取H264裸流并保存到文件中 工程

思考,这里就有两个问题未完成,一个就是怎么将 H265的裸流保存到文件,再有怎么保存成其他格式比如MP4。

保存到MP4文件代码如下:

    1. #include "stdafx.h"
    2. #ifdef __cplusplus
    3. extern "C" {
    4. #endif
    5. #include <libavcodec/avcodec.h>
    6. #include <libavdevice/avdevice.h>
    7. #include <libavformat/avformat.h>
    8. #include <libavfilter/avfilter.h>
    9. #include <libavutil/avutil.h>
    10. #include <libswscale/swscale.h>
    11. #include <stdlib.h>
    12. #include <stdio.h>
    13. #include <string.h>
    14. #include <math.h>
    15. #ifdef __cplusplus
    16. }
    17. #endif
    18. AVFormatContext *i_fmt_ctx;
    19. AVStream *i_video_stream;
    20. AVFormatContext *o_fmt_ctx;
    21. AVStream *o_video_stream;
    22. int _tmain(int argc, char **argv)
    23. {
    24. avcodec_register_all();
    25. av_register_all();
    26. avformat_network_init();
    27. /* should set to NULL so that avformat_open_input() allocate a new one */
    28. i_fmt_ctx = NULL;
    29. char rtspUrl[] = "rtsp://192.168.2.xx:8554/H264unicast";
    30. const char *filename = "1.mp4";
    31. if (avformat_open_input(&i_fmt_ctx, rtspUrl, NULL, NULL) != 0)
    32. {
    33. fprintf(stderr, "could not open input file\n");
    34. return -1;
    35. }
    36. if (avformat_find_stream_info(i_fmt_ctx, NULL)<0)
    37. {
    38. fprintf(stderr, "could not find stream info\n");
    39. return -1;
    40. }
    41. //av_dump_format(i_fmt_ctx, 0, argv[1], 0);
    42. /* find first video stream */
    43. for (unsigned i = 0; i<i_fmt_ctx->nb_streams; i++)
    44. {
    45. if (i_fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
    46. {
    47. i_video_stream = i_fmt_ctx->streams[i];
    48. break;
    49. }
    50. }
    51. if (i_video_stream == NULL)
    52. {
    53. fprintf(stderr, "didn't find any video stream\n");
    54. return -1;
    55. }
    56. avformat_alloc_output_context2(&o_fmt_ctx, NULL, NULL, filename);
    57. /*
    58. * since all input files are supposed to be identical (framerate, dimension, color format, ...)
    59. * we can safely set output codec values from first input file
    60. */
    61. o_video_stream = avformat_new_stream(o_fmt_ctx, NULL);
    62. {
    63. AVCodecContext *c;
    64. c = o_video_stream->codec;
    65. c->bit_rate = 400000;
    66. c->codec_id = i_video_stream->codec->codec_id;
    67. c->codec_type = i_video_stream->codec->codec_type;
    68. c->time_base.num = i_video_stream->time_base.num;
    69. c->time_base.den = i_video_stream->time_base.den;
    70. fprintf(stderr, "time_base.num = %d time_base.den = %d\n", c->time_base.num, c->time_base.den);
    71. c->width = i_video_stream->codec->width;
    72. c->height = i_video_stream->codec->height;
    73. c->pix_fmt = i_video_stream->codec->pix_fmt;
    74. printf("%d %d %d", c->width, c->height, c->pix_fmt);
    75. c->flags = i_video_stream->codec->flags;
    76. c->flags |= CODEC_FLAG_GLOBAL_HEADER;
    77. c->me_range = i_video_stream->codec->me_range;
    78. c->max_qdiff = i_video_stream->codec->max_qdiff;
    79. c->qmin = i_video_stream->codec->qmin;
    80. c->qmax = i_video_stream->codec->qmax;
    81. c->qcompress = i_video_stream->codec->qcompress;
    82. }
    83. avio_open(&o_fmt_ctx->pb, filename, AVIO_FLAG_WRITE);
    84. avformat_write_header(o_fmt_ctx, NULL);
    85. int last_pts = 0;
    86. int last_dts = 0;
    87. int64_t pts, dts;
    88. while (1)
    89. {
    90. AVPacket i_pkt;
    91. av_init_packet(&i_pkt);
    92. i_pkt.size = 0;
    93. i_pkt.data = NULL;
    94. if (av_read_frame(i_fmt_ctx, &i_pkt) <0)
    95. break;
    96. /*
    97. * pts and dts should increase monotonically
    98. * pts should be >= dts
    99. */
    100. i_pkt.flags |= AV_PKT_FLAG_KEY;
    101. pts = i_pkt.pts;
    102. i_pkt.pts += last_pts;
    103. dts = i_pkt.dts;
    104. i_pkt.dts += last_dts;
    105. i_pkt.stream_index = 0;
    106. //printf("%lld %lld\n", i_pkt.pts, i_pkt.dts);
    107. static int num = 1;
    108. printf("frame %d\n", num++);
    109. av_interleaved_write_frame(o_fmt_ctx, &i_pkt);
    110. //av_free_packet(&i_pkt);
    111. //av_init_packet(&i_pkt);
    112. }
    113. last_dts += dts;
    114. last_pts += pts;
    115. avformat_close_input(&i_fmt_ctx);
    116. av_write_trailer(o_fmt_ctx);
    117. avcodec_close(o_fmt_ctx->streams[0]->codec);
    118. av_freep(&o_fmt_ctx->streams[0]->codec);
    119. av_freep(&o_fmt_ctx->streams[0]);
    120. avio_close(o_fmt_ctx->pb);
    121. av_free(o_fmt_ctx);
    122. return 0;
    123. }

最新文章

  1. ASP.NET MVC5----基本用法
  2. 点击每个li节点,都弹出其文本值及修改
  3. js购物车计算价格
  4. python中的生成器
  5. 转: ios app架构设计
  6. ASP.NET程序如何更新发布
  7. poj2069
  8. centos6.8 静默安装 oracle 11.2.0.4
  9. 排座椅 2008 NOIP 普及组 第二题
  10. 练习使用markdown
  11. WDA的配置
  12. 在Nginx上配置多个站点
  13. 数据挖掘进阶之序列模式分析算法GSP的实现
  14. Git常用命令拾遗
  15. 利用Navicat高效率postgresql转mysql数据库
  16. P1605 迷宫
  17. DES、RC4、AES等加密算法优势及应用
  18. 洛谷 P1457 城堡 The Castle 解题报告
  19. [spring] 对实体 &quot;characterEncoding&quot; 的引用必须以 &#39;;&#39; 分隔符结尾
  20. view添加虚线边框

热门文章

  1. IDEA安装codota插件和使用,开发人员的知心伙伴
  2. Java程序入门
  3. RESTful风格、异常处理、Spring框架
  4. windows中使用django时报错:A server error occurred. Please contact the administrator.
  5. 转 Fiddler4 手机抓包
  6. 1.Spring的基本应用
  7. mybatis源码分析之走进缓存
  8. 列出HBASE所有表的相关信息,如表名、创建时间等。
  9. Boyer-Moore 投票算法
  10. Linux监控内核SNMP计数器