FFMPEG 从rtsp抓取流,转存为flv文件

点击打开链接

[cpp]  view plain  copy
  1. #include<stdio.h>  
  2.   
  3. #define __STDC_CONSTANT_MACROS  
  4.   
  5. #ifdef __cplusplus  
  6. extern "C"  
  7. {  
  8. #endif  
  9.   
  10. #include<libavformat/avformat.h>  
  11. #include<libavutil/mathematics.h>  
  12. #include<libavutil/time.h>  
  13.   
  14. #ifdef __cplusplus  
  15. }  
  16. #endif  
  17.   
  18.   
  19. int main(int argc,char **argv)  
  20. {  
  21.     AVOutputFormat *ofmt = NULL;  
  22.     AVFormatContext *ifmt_ctx = NULL,*ofmt_ctx = NULL;  
  23.     AVPacket pkt;  
  24.     const char *in_filename,*out_filename;      
  25.     int ret,i;  
  26.     int video_index=-1;  
  27.     int frame_index=0;  
  28.     in_filename="rtsp://admin:[email protected]:554/";  
  29.     out_filename="receive.flv";  
  30.   
  31.     av_register_all();  
  32.     avformat_network_init();  
  33.   
  34.     //使用TCP连接打开RTSP,设置最大延迟时间  
  35.     AVDictionary *avdic=NULL;    
  36.     char option_key[]="rtsp_transport";    
  37.     char option_value[]="tcp";    
  38.     av_dict_set(&avdic,option_key,option_value,0);    
  39.     char option_key2[]="max_delay";    
  40.     char option_value2[]="5000000";    
  41.     av_dict_set(&avdic,option_key2,option_value2,0);   
  42.     //打开输入流  
  43.     if((ret=avformat_open_input(&ifmt_ctx,in_filename,0,&avdic))<0)  
  44.     {  
  45.         printf("Could not open input file.\n");  
  46.         goto end;  
  47.     }  
  48.     if((ret=avformat_find_stream_info(ifmt_ctx,0))<0)  
  49.     {  
  50.         printf("Failed to retrieve input stream information\n");  
  51.         goto end;  
  52.     }  
  53.     //nb_streams代表有几路流,一般是2路:即音频和视频,顺序不一定  
  54.     for(i=0;i<ifmt_ctx->nb_streams;i++){  
  55.           
  56.         if(ifmt_ctx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)  
  57.         {  
  58.             //这一路是视频流,标记一下,以后取视频流都从ifmt_ctx->streams[video_index]取  
  59.             video_index=i;  
  60.             break;  
  61.         }  
  62.     }  
  63.   
  64.     av_dump_format(ifmt_ctx,0,in_filename,0);  
  65.   
  66.     //打开输出流  
  67.     avformat_alloc_output_context2(&ofmt_ctx,NULL,NULL,out_filename);  
  68.       
  69.     if(!ofmt_ctx)  
  70.     {  
  71.         printf("Could not create output context\n");  
  72.         ret=AVERROR_UNKNOWN;  
  73.         goto end;  
  74.     }  
  75.       
  76.     ofmt = ofmt_ctx->oformat;  
  77.     for(i=0;i<ifmt_ctx->nb_streams;i++)  
  78.     {    //根据输入流创建输出流  
  79.         AVStream *in_stream = ifmt_ctx->streams[i];  
  80.         AVStream *out_stream = avformat_new_stream(ofmt_ctx,in_stream->codec->codec);  
  81.         if(!out_stream)  
  82.         {  
  83.             printf("Failed allocating output stream.\n");  
  84.             ret = AVERROR_UNKNOWN;  
  85.             goto end;  
  86.         }  
  87.   
  88.         //将输出流的编码信息复制到输入流  
  89.         ret = avcodec_copy_context(out_stream->codec,in_stream->codec);  
  90.         if(ret<0)  
  91.         {  
  92.             printf("Failed to copy context from input to output stream codec context\n");  
  93.             goto end;  
  94.         }  
  95.         out_stream->codec->codec_tag = 0;  
  96.       
  97.         if(ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)  
  98.             out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;  
  99.   
  100.     }  
  101.   
  102.     //Dump format--------------------  
  103.     av_dump_format(ofmt_ctx,0,out_filename,1);  
  104.     //打开输出文件  
  105.     if(!(ofmt->flags & AVFMT_NOFILE))  
  106.     {  
  107.         ret = avio_open(&ofmt_ctx->pb,out_filename,AVIO_FLAG_WRITE);  
  108.         if(ret<0)  
  109.         {  
  110.             printf("Could not open output URL '%s'",out_filename);  
  111.             goto end;  
  112.         }  
  113.     }  
  114.   
  115.     //写文件头到输出文件  
  116.     ret = avformat_write_header(ofmt_ctx,NULL);  
  117.     if(ret < 0)  
  118.     {  
  119.         printf("Error occured when opening output URL\n");  
  120.         goto end;  
  121.     }  
  122.   
  123.   
  124.     //while循环中持续获取数据包,不管音频视频都存入文件  
  125.     while(1)  
  126.     {  
  127.         AVStream *in_stream,*out_stream;  
  128.         //从输入流获取一个数据包  
  129.         ret = av_read_frame(ifmt_ctx,&pkt);  
  130.         if(ret<0)  
  131.             break;  
  132.   
  133.         in_stream = ifmt_ctx->streams[pkt.stream_index];  
  134.         out_stream = ofmt_ctx->streams[pkt.stream_index];  
  135.         //copy packet  
  136.         //转换 PTS/DTS 时序  
  137.         pkt.pts = av_rescale_q_rnd(pkt.pts,in_stream->time_base,out_stream->time_base,(enum AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));  
  138.         pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, (enum AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));    
  139.         //printf("pts %d dts %d base %d\n",pkt.pts,pkt.dts, in_stream->time_base);  
  140.         pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);   
  141.         pkt.pos = -1;    
  142.   
  143.         //此while循环中并非所有packet都是视频帧,当收到视频帧时记录一下,仅此而已  
  144.         if(pkt.stream_index==video_index)  
  145.         {  
  146.             printf("Receive %8d video frames from input URL\n",frame_index);  
  147.             frame_index++;  
  148.         }  
  149.   
  150.         //将包数据写入到文件。  
  151.         ret = av_interleaved_write_frame(ofmt_ctx,&pkt);  
  152.         if(ret < 0)  
  153.         {  
  154.             /** 
  155.             当网络有问题时,容易出现到达包的先后不一致,pts时序混乱会导致 
  156.             av_interleaved_write_frame函数报 -22 错误。暂时先丢弃这些迟来的帧吧 
  157.             若所大部分包都没有pts时序,那就要看情况自己补上时序(比如较前一帧时序+1)再写入。 
  158.             */  
  159.             if(ret==-22){  
  160.                 continue;  
  161.             }else{  
  162.                 printf("Error muxing packet.error code %d\n" , ret);  
  163.                 break;  
  164.             }  
  165.               
  166.         }  
  167.           
  168.         //av_free_packet(&pkt); //此句在新版本中已deprecated 由av_packet_unref代替  
  169.         av_packet_unref(&pkt);  
  170.     }  
  171.   
  172.   
  173.     //写文件尾  
  174.     av_write_trailer(ofmt_ctx);  
  175.   
  176. end:  
  177.       
  178.     av_dict_free(&avdic);  
  179.     avformat_close_input(&ifmt_ctx);  
  180.     //Close input  
  181.     if(ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))  
  182.         avio_close(ofmt_ctx->pb);  
  183.     avformat_free_context(ofmt_ctx);  
  184.     if(ret<0 && ret != AVERROR_EOF)  
  185.     {  
  186.         printf("Error occured.\n");  
  187.         return -1;  
  188.     }  
  189.     return 0;  
  190.       
  191. }  

猜你喜欢

转载自blog.csdn.net/maigao1/article/details/79229468
今日推荐