音视频开发(17)---RTSP再学习 -- 利用FFmpeg 将 rtsp 获取H264裸流并保存到文件中

RTSP再学习 -- 利用FFmpeg 将 rtsp 获取H264裸流并保存到文件中

https://blog.csdn.net/qq_29350001/article/details/78214267

既然已经可以通过 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.  
  3. #include <stdio.h>

  4.  
  5. #define __STDC_CONSTANT_MACROS

  6.  
  7. #ifdef _WIN32

  8. //Windows

  9. extern "C"

  10. {

  11. #include "libavcodec/avcodec.h"

  12. #include "libavformat/avformat.h"

  13. #include "libswscale/swscale.h"

  14. #include "SDL2/SDL.h"

  15. };

  16. #else

  17. //Linux...

  18. #ifdef __cplusplus

  19. extern "C"

  20. {

  21. #endif

  22. #include <libavcodec/avcodec.h>

  23. #include <libavformat/avformat.h>

  24. #include <libswscale/swscale.h>

  25. #include <SDL2/SDL.h>

  26. #ifdef __cplusplus

  27. };

  28. #endif

  29. #endif

  30.  
  31. int main(int argc, char* argv[])

  32. {

  33.  
  34. AVFormatContext *pFormatCtx;

  35. int i, videoindex;

  36. AVCodecContext *pCodecCtx;

  37. AVCodec *pCodec;

  38. AVFrame *pFrame, *pFrameYUV;

  39. uint8_t *out_buffer;

  40. AVPacket *packet;

  41. int ret, got_picture;

  42.  
  43.  
  44. struct SwsContext *img_convert_ctx;

  45. // 改成你自己的 URL

  46. char filepath[] = "rtsp://192.168.2.xx:8554/1";

  47. av_register_all();

  48. avformat_network_init();

  49. pFormatCtx = avformat_alloc_context();

  50.  
  51. if (avformat_open_input(&pFormatCtx, filepath, NULL, NULL) != 0)打开网络流或文件流

  52. {

  53. printf("Couldn't open input stream.\n");

  54. return -1;

  55. }

  56. if (avformat_find_stream_info(pFormatCtx, NULL)<0)

  57. {

  58. printf("Couldn't find stream information.\n");

  59. return -1;

  60. }

  61. videoindex = -1;

  62. for (i = 0; i<pFormatCtx->nb_streams; i++)

  63. if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)

  64. {

  65. videoindex = i;

  66. break;

  67. }

  68. if (videoindex == -1)

  69. {

  70. printf("Didn't find a video stream.\n");

  71. return -1;

  72. }

  73. pCodecCtx = pFormatCtx->streams[videoindex]->codec;

  74. pCodec = avcodec_find_decoder(pCodecCtx->codec_id);

  75. if (pCodec == NULL)

  76. {

  77. printf("Codec not found.\n");

  78. return -1;

  79. }

  80. if (avcodec_open2(pCodecCtx, pCodec, NULL)<0)

  81. {

  82. printf("Could not open codec.\n");

  83. return -1;

  84. }

  85. pFrame = av_frame_alloc();

  86. pFrameYUV = av_frame_alloc();

  87. out_buffer = (uint8_t *)av_malloc(avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));

  88. avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);

  89.  
  90. //Output Info---输出一些文件(RTSP)信息

  91. printf("---------------- File Information ---------------\n");

  92. av_dump_format(pFormatCtx, 0, filepath, 0);

  93. printf("-------------------------------------------------\n");

  94.  
  95. img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,

  96. pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);

  97.  
  98.  
  99. packet = (AVPacket *)av_malloc(sizeof(AVPacket));

  100.  
  101. FILE *fpSave;

  102. if ((fpSave = fopen("geth264.h264", "ab")) == NULL) //h264保存的文件名

  103. return 0;

  104. for (;;)

  105. {

  106. //------------------------------

  107. if (av_read_frame(pFormatCtx, packet) >= 0)

  108. {

  109. if (packet->stream_index == videoindex)

  110. {

  111. fwrite(packet->data, 1, packet->size, fpSave);//写数据到文件中

  112. }

  113. av_free_packet(packet);

  114. }

  115. }

  116.  
  117.  
  118. //--------------

  119. av_frame_free(&pFrameYUV);

  120. av_frame_free(&pFrame);

  121. avcodec_close(pCodecCtx);

  122. avformat_close_input(&pFormatCtx);

  123.  
  124. return 0;

  125. }

 

 

调试结果显示如下:


 

生成 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.  
  19. AVFormatContext *i_fmt_ctx;

  20. AVStream *i_video_stream;

  21. AVFormatContext *o_fmt_ctx;

  22. AVStream *o_video_stream;

  23.  
  24. int _tmain(int argc, char **argv)

  25. {

  26. avcodec_register_all();

  27. av_register_all();

  28. avformat_network_init();

  29.  
  30. /* should set to NULL so that avformat_open_input() allocate a new one */

  31. i_fmt_ctx = NULL;

  32. char rtspUrl[] = "rtsp://192.168.2.xx:8554/H264unicast";

  33. const char *filename = "1.mp4";

  34. if (avformat_open_input(&i_fmt_ctx, rtspUrl, NULL, NULL) != 0)

  35. {

  36. fprintf(stderr, "could not open input file\n");

  37. return -1;

  38. }

  39.  
  40. if (avformat_find_stream_info(i_fmt_ctx, NULL)<0)

  41. {

  42. fprintf(stderr, "could not find stream info\n");

  43. return -1;

  44. }

  45.  
  46. //av_dump_format(i_fmt_ctx, 0, argv[1], 0);

  47.  
  48. /* find first video stream */

  49. for (unsigned i = 0; i<i_fmt_ctx->nb_streams; i++)

  50. {

  51. if (i_fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)

  52. {

  53. i_video_stream = i_fmt_ctx->streams[i];

  54. break;

  55. }

  56. }

  57. if (i_video_stream == NULL)

  58. {

  59. fprintf(stderr, "didn't find any video stream\n");

  60. return -1;

  61. }

  62.  
  63. avformat_alloc_output_context2(&o_fmt_ctx, NULL, NULL, filename);

  64.  
  65. /*

  66. * since all input files are supposed to be identical (framerate, dimension, color format, ...)

  67. * we can safely set output codec values from first input file

  68. */

  69. o_video_stream = avformat_new_stream(o_fmt_ctx, NULL);

  70. {

  71. AVCodecContext *c;

  72. c = o_video_stream->codec;

  73. c->bit_rate = 400000;

  74. c->codec_id = i_video_stream->codec->codec_id;

  75. c->codec_type = i_video_stream->codec->codec_type;

  76. c->time_base.num = i_video_stream->time_base.num;

  77. c->time_base.den = i_video_stream->time_base.den;

  78. fprintf(stderr, "time_base.num = %d time_base.den = %d\n", c->time_base.num, c->time_base.den);

  79. c->width = i_video_stream->codec->width;

  80. c->height = i_video_stream->codec->height;

  81. c->pix_fmt = i_video_stream->codec->pix_fmt;

  82. printf("%d %d %d", c->width, c->height, c->pix_fmt);

  83. c->flags = i_video_stream->codec->flags;

  84. c->flags |= CODEC_FLAG_GLOBAL_HEADER;

  85. c->me_range = i_video_stream->codec->me_range;

  86. c->max_qdiff = i_video_stream->codec->max_qdiff;

  87. c->qmin = i_video_stream->codec->qmin;

  88. c->qmax = i_video_stream->codec->qmax;

  89. c->qcompress = i_video_stream->codec->qcompress;

  90. }

  91.  
  92. avio_open(&o_fmt_ctx->pb, filename, AVIO_FLAG_WRITE);

  93. avformat_write_header(o_fmt_ctx, NULL);

  94.  
  95. int last_pts = 0;

  96. int last_dts = 0;

  97. int64_t pts, dts;

  98. while (1)

  99. {

  100. AVPacket i_pkt;

  101. av_init_packet(&i_pkt);

  102. i_pkt.size = 0;

  103. i_pkt.data = NULL;

  104. if (av_read_frame(i_fmt_ctx, &i_pkt) <0)

  105. break;

  106. /*

  107. * pts and dts should increase monotonically

  108. * pts should be >= dts

  109. */

  110. i_pkt.flags |= AV_PKT_FLAG_KEY;

  111. pts = i_pkt.pts;

  112. i_pkt.pts += last_pts;

  113. dts = i_pkt.dts;

  114. i_pkt.dts += last_dts;

  115. i_pkt.stream_index = 0;

  116.  
  117. //printf("%lld %lld\n", i_pkt.pts, i_pkt.dts);

  118. static int num = 1;

  119. printf("frame %d\n", num++);

  120. av_interleaved_write_frame(o_fmt_ctx, &i_pkt);

  121. //av_free_packet(&i_pkt);

  122. //av_init_packet(&i_pkt);

  123. }

  124. last_dts += dts;

  125. last_pts += pts;

  126. avformat_close_input(&i_fmt_ctx);

  127. av_write_trailer(o_fmt_ctx);

  128. avcodec_close(o_fmt_ctx->streams[0]->codec);

  129. av_freep(&o_fmt_ctx->streams[0]->codec);

  130. av_freep(&o_fmt_ctx->streams[0]);

  131. avio_close(o_fmt_ctx->pb);

  132. av_free(o_fmt_ctx);

  133. return 0;

  134. }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值