利用FFmpeg 将 rtsp 获取H264裸流并保存到文件中

既然已经可以通过 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. }

调试结果显示如下:

利用FFmpeg 将 rtsp 获取H264裸流并保存到文件中

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

利用FFmpeg 将 rtsp 获取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. }
上一篇:javascript引擎执行的过程的理解--语法分析和预编译阶段


下一篇:PHP页面间参数传递的四种方法详解