RTSP再学习 -- 利用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原始码流保存到文件中

[cpp]  view plain  copy
  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文件代码如下:

[cpp]  view plain  copy
  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. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值