ffmpeg API录制rtsp视频流

时间:2022-12-13 23:40:20

原文出自http://blog.****.net/zxwangyun/article/details/8190638#reply   作者 Sloan

 

这里在录制时,并没有进行转码,只是相当于把rtsp视频直接保存到一个文件中。

  1. #include <stdio.h>   
  2.   
  3. #ifdef __cplusplus   
  4. extern "C" {  
  5. #endif   
  6. #include <libavcodec/avcodec.h>   
  7. #include <libavformat/avformat.h>   
  8. //#include <libswscale/swscale.h>   
  9.   
  10. #ifdef _MSC_VER   
  11. int strcasecmp(const char *s1, const char *s2)  
  12. {  
  13.     while ((*s1 != '\0')  
  14.         && (tolower(*(unsigned char *) s1) ==  
  15.         tolower(*(unsigned char *) s2)))   
  16.     {  
  17.         s1++;  
  18.         s2++;  
  19.     }  
  20.   
  21.     return tolower(*(unsigned char *) s1) - tolower(*(unsigned char *) s2);  
  22. }  
  23. int strncasecmp(const char *s1, const char *s2, unsigned int n)  
  24. {  
  25.     if (n == 0)  
  26.         return 0;  
  27.   
  28.     while ((n-- != 0)  
  29.         && (tolower(*(unsigned char *) s1) ==  
  30.         tolower(*(unsigned char *) s2))) {  
  31.             if (n == 0 || *s1 == '\0' || *s2 == '\0')  
  32.                 return 0;  
  33.             s1++;  
  34.             s2++;  
  35.     }  
  36.   
  37.     return tolower(*(unsigned char *) s1) - tolower(*(unsigned char *) s2);  
  38. }  
  39. #endif //_MSC_VER   
  40.   
  41. #ifdef __cplusplus   
  42. }  
  43. #endif   
  44.   
  45. /*********************************************************** 
  46. '** stream_component_open 
  47. *   Description:  
  48. *            //open the stream component for video/audio 
  49. * 
  50. * 
  51. *   Params:ic-pointer which contains the url and codec details  
  52. :stream_index-index denoting video or audio stream 
  53. ***********************************************************/  
  54. int stream_component_open(AVFormatContext *ic, int stream_index)  
  55. {  
  56.     AVCodecContext *enc;  
  57.     AVCodec *codec;  
  58.   
  59.     if (stream_index < 0 || stream_index >= (int)ic->nb_streams)  
  60.         return -1;  
  61.     enc = ic->streams[stream_index]->codec;  
  62.   
  63.     /* prepare audio output */  
  64.     if (enc->codec_type == CODEC_TYPE_AUDIO)  
  65.     {  
  66.         if (enc->channels > 0)  
  67.             enc->request_channels = FFMIN(2, enc->channels);  
  68.         else  
  69.             enc->request_channels = 2;  
  70.   
  71.         /*Hardcoding the codec id to PCM_MULAW if the audio 
  72.         codec id returned by the lib is CODEC_ID_NONE */  
  73.   
  74.         if(enc->codec_id == CODEC_ID_NONE)  
  75.         {  
  76.             enc->codec_id = CODEC_ID_PCM_MULAW;  
  77.             enc->channels = 1;  
  78.             enc->sample_rate = 16000;  
  79.             enc->bit_rate = 128;  
  80.         }  
  81.     }  
  82.   
  83.     codec = avcodec_find_decoder(enc->codec_id);  
  84.     enc->idct_algo           = FF_IDCT_AUTO;  
  85.     enc->flags2   |= CODEC_FLAG2_FAST;  
  86.     enc->skip_frame          = AVDISCARD_DEFAULT;  
  87.     enc->skip_idct           = AVDISCARD_DEFAULT;  
  88.     enc->skip_loop_filter    = AVDISCARD_DEFAULT;  
  89.     enc->error_concealment   = 3;  
  90.   
  91.     if (!codec || avcodec_open(enc, codec) < 0)  
  92.         return -1;  
  93.     avcodec_thread_init(enc, 1);  
  94.     enc->thread_count= 1;  
  95.     ic->streams[stream_index]->discard = AVDISCARD_DEFAULT;  
  96.   
  97.     return 0;  
  98. }  
  99. //声明函数   
  100. int enable_local_record(AVFormatContext *ic/*已经打开的视频文件上下文*/,  
  101.                         int videostream,int audiostream,  
  102.                         AVFormatContext **out_oc,const char * ofile,const char * ofileformat);  
  103.   
  104. int exit_onerr(const char * err_desc/*错误描述*/,int err_code/*错误码*/)  
  105. {  
  106.     printf("%s\n",err_desc);  
  107.     system("pause");//暂停,查看错误描述   
  108.     return err_code;  
  109. }  
  110. int main(int argc, char* argv[])  
  111. {  
  112.     //初始化ffmpeg链表结构   
  113.     avcodec_register_all();                     // Register all formats and codecs   
  114.     av_register_all();  
  115.   
  116.     AVPacket  packet;  
  117.   
  118.     //打开文件   
  119.     AVFormatContext * ic = NULL;  
  120.     const char * rtsp_url = "rtsp://192.168.0.168:8557/PSIA/Streaming/channels/2?videoCodecType=H.264";  
  121.     if(av_open_input_file(&ic, rtsp_url, NULL, 0, NULL)!=0)  
  122.     {                         
  123.         return exit_onerr("can't open file.",-1);  
  124.     }  
  125.     if(!ic)  
  126.     {  
  127.         return exit_onerr("unknow error.",-2);  
  128.     }  
  129.     ic ->max_analyze_duration = 1000;  
  130.   
  131.     //get streams information   
  132.     if(av_find_stream_info(ic)<0)  
  133.     {  
  134.         av_close_input_file(ic);//退出前,记得释放资源   
  135.         ic = NULL;  
  136.         return exit_onerr("con't init streams information.",-3);  
  137.     }  
  138.   
  139.   
  140.     //find stream   
  141.     int videoStream=-1; // Didn't find a video stream   
  142.     int audioStream=-1; // Didn't find a audio stream    
  143.     // Find the first video stream   
  144.     for(int i=0; i<ic ->nb_streams; i++)  
  145.     {  
  146.         if( ic ->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO)  
  147.         {   
  148.             videoStream=i;  
  149.             break;  
  150.         }  
  151.     }  
  152.     // Find the first audio stream   
  153.     for(int i=0; i<ic ->nb_streams; i++)  
  154.     {  
  155.         if( ic ->streams[i]->codec->codec_type==CODEC_TYPE_AUDIO)  
  156.         {  
  157.             audioStream=i;  
  158.             break;  
  159.         }  
  160.     }  
  161.     //判断视频文件中是否包含音视频流,如果没有,退出   
  162.     if(audioStream<0 && videoStream<0)  
  163.     {  
  164.         av_close_input_file(ic);//退出前,记得释放资源   
  165.         ic = NULL;  
  166.         return exit_onerr("con't find a audio stream or video stream",-4);  
  167.     }  
  168.   
  169.     //open the stream component for video   
  170.     int videoComponent = -1;  
  171.     if(videoStream >= 0)  
  172.     {  
  173.         videoComponent = stream_component_open(ic, videoStream);   
  174.         if(videoComponent<0)  
  175.         {  
  176.             av_close_input_file(ic);//退出前,记得释放资源   
  177.             return exit_onerr("not supported video stream",-5);//要求重新编译ffmpeg以支持该种编码格式   
  178.         }  
  179.     }  
  180.     //open the stream component for audio   
  181.     int audioComponent = -1;  
  182.     if(audioStream >= 0)  
  183.     {  
  184.         audioComponent = stream_component_open(ic, audioStream);   
  185.         if(audioComponent<0)  
  186.         {  
  187.             av_close_input_file(ic);//退出前,记得释放资源   
  188.             return exit_onerr("not supported audio stream",-6);//要求重新编译ffmpeg以支持该种编码格式   
  189.         }  
  190.     }  
  191.   
  192.   
  193.     //////////////////////////////////////////////////////   
  194.     int ret = 0;  
  195.     //初始化并打开录像   
  196.     AVFormatContext * oc = NULL;  
  197.     const char * out_file_name = "D:\\test.avi";  
  198.   
  199.     //获取一帧完整的图像用于初始化ffmpeg内部的一些结构体数据(这里使用什么数据尚未清楚,请自行查看),否则会出现写文件头失败   
  200.     int got_picture = 0;  
  201.     AVFrame *frame = avcodec_alloc_frame();  
  202.     while( 1 )  
  203.     {  
  204.         if(av_read_frame( ic, &packet)<0)  
  205.         {  
  206.             av_free_packet(&packet);  
  207.             av_close_input_file(ic);//退出前,记得释放资源   
  208.             return exit_onerr("read frame error.",-7);//读取视频帧失败   
  209.         }  
  210.         if(packet.stream_index == videoStream)  
  211.         {  
  212.             avcodec_decode_video(ic->streams[videoStream]->codec, frame, &got_picture, packet.data, packet.size);  
  213.         }  
  214.         av_free_packet(&packet);  
  215.         if(got_picture)  
  216.             break;  
  217.     }  
  218.     av_free(frame);  
  219.   
  220.     ret = enable_local_record(ic,videoStream,audioStream,&oc,out_file_name,"avi");  
  221.   
  222.     if(ret <0 || !oc)  
  223.     {  
  224.         //退出前,记得释放资源,现在又多了个oc参数需要释放   
  225.         if(oc)  
  226.         {  
  227.             ///cleanup the output contents format   
  228.             for(unsigned int i=0;i< oc->nb_streams;i++)  
  229.             {  
  230.                 av_metadata_free(&oc ->streams[i]->metadata);  
  231.                 av_free(oc ->streams[i]->codec);  
  232.                 av_free(oc ->streams[i]);  
  233.             }  
  234.             for(unsigned int i=0;i<oc ->nb_programs;i++)   
  235.             {  
  236.                 av_metadata_free(&oc ->programs[i]->metadata);  
  237.             }  
  238.             for(unsigned int i=0;i<oc ->nb_chapters;i++)   
  239.             {  
  240.                 av_metadata_free(&oc ->chapters[i]->metadata);  
  241.             }  
  242.             av_metadata_free(&oc ->metadata);  
  243.             av_free(oc);  
  244.         }  
  245.         av_close_input_file(ic);  
  246.         return exit_onerr("can't init out file.",-8);  
  247.     }  
  248.   
  249.     //开始录像   
  250.     int video_dts = 0,audio_dts = 0;//时间戳   
  251.     int total_frame = 300;//写300帧文件   
  252.     while(total_frame--)  
  253.     {  
  254.         if( av_read_frame( ic, &packet) <0 )     //read the packet   
  255.         {         
  256.             //读取数据出错   
  257.             av_free_packet(&packet);  
  258.             break;  
  259.         }  
  260.         if(packet.data && (packet.stream_index == videoStream || packet.stream_index == audioStream) )  
  261.         {  
  262.             //计算时间视频戳,顺序+1,这里可以多研究几种编码的音视频文件,求其时间戳生成格式,h264编码顺序加1即可   
  263.             if(packet.stream_index == videoStream)  
  264.             {  
  265.                 packet.dts = video_dts++;  
  266.                 packet.pts = video_dts;  
  267.             }  
  268.             else if(packet.stream_index == audioStream)//计算音频时间戳   
  269.             {  
  270.                 packet.dts = audio_dts++;  
  271.                 packet.pts = audio_dts * (1000 * packet.size /ic ->streams[packet.stream_index]->codec ->sample_rate);  
  272.             }  
  273.             packet.flags |= PKT_FLAG_KEY;  
  274.             if(av_interleaved_write_frame(oc,&packet)<0)  
  275.             {  
  276.                 printf("st:%d\twrite frame failed.\n",packet.stream_index);  
  277.             }  
  278.         }  
  279.         av_free_packet(&packet);  
  280.     }  
  281.   
  282.     //关闭录像文件和输入文件   
  283.   
  284.     //写文件尾   
  285.     av_write_trailer(oc);  
  286.   
  287.     /* close the output file if need.*/  
  288.     if (!(oc ->oformat->flags & AVFMT_NOFILE))   
  289.     {  
  290.         url_fclose(oc->pb);  
  291.     }  
  292.   
  293.     //释放资源   
  294.     /*cleanup the output contents format*/  
  295.     for(unsigned int i=0;i< oc->nb_streams;i++)  
  296.     {  
  297.         av_metadata_free(&oc ->streams[i]->metadata);  
  298.         av_free(oc ->streams[i]->codec);  
  299.         av_free(oc ->streams[i]);  
  300.     }  
  301.     for(unsigned int i=0;i<oc ->nb_programs;i++)   
  302.     {  
  303.         av_metadata_free(&oc ->programs[i]->metadata);  
  304.     }  
  305.     for(unsigned int i=0;i<oc ->nb_chapters;i++)   
  306.     {  
  307.         av_metadata_free(&oc ->chapters[i]->metadata);  
  308.     }  
  309.     av_metadata_free(&oc ->metadata);  
  310.     av_free(oc);  
  311.   
  312.     av_close_input_file(ic);  
  313.   
  314.     return 0;  
  315. }  
  316.   
  317. //初始化录像文件,代码较长,可写成函数   
  318. /* 
  319. *return <0  failed, 0 success 
  320. */  
  321. int enable_local_record(AVFormatContext *ic/*已经打开的视频文件上下文*/,int videostream,int audiostream,AVFormatContext **out_oc,const char * ofile,const char * ofileformat)  
  322. {  
  323.     AVFormatContext *oc     = NULL;//   
  324.     AVOutputFormat  *fmt    = NULL;  
  325.   
  326.     if( ofileformat )  
  327.     {  
  328.         fmt = av_guess_format(ofileformat, NULL, NULL);  
  329.     }  
  330.     if(!fmt)  
  331.     {  
  332.         printf("out file format \"%s\" invalidate.\n",ofileformat);  
  333.         return -1;  
  334.     }  
  335.   
  336.     /*******************************************init output contents begin**********************************************************/  
  337.     /* allocate the output media context */  
  338.     oc = avformat_alloc_context();  
  339.     if (!oc)   
  340.     {  
  341.         printf("out of memory.\n");  
  342.         return -2;//内存分配失败   
  343.     }  
  344.   
  345.     *out_oc = oc;  
  346.   
  347.     oc ->oformat = fmt;  
  348.     sprintf_s( oc ->filename, sizeof( oc ->filename), "%s", ofile);  
  349.     av_metadata_conv(oc, fmt->metadata_conv, NULL);  
  350.     if( videostream >=0 )  
  351.     {  
  352.         //AVCodecContext* pCodecCtx= ->streams[videostream]->codec;;   
  353.         //add video stream   
  354.         AVStream * st = av_new_stream(oc, videostream);  
  355.         if(!st)  
  356.         {  
  357.             printf("can not add a video stream.\n");  
  358.             return -3;  
  359.         }  
  360.         st->codec->codec_id           =  ic ->streams[videostream] ->codec->codec_id;  
  361.         st->codec->codec_type     =  CODEC_TYPE_VIDEO;  
  362.         st->codec->bit_rate           =  ic ->streams[videostream] ->codec->bit_rate;  
  363.         st->codec->width          =  ic ->streams[videostream] ->codec->width;  
  364.         st->codec->height         =  ic ->streams[videostream] ->codec->height;  
  365.         st->codec->gop_size           =  ic ->streams[videostream] ->codec->gop_size;  
  366.         st->codec->pix_fmt            =  ic ->streams[videostream] ->codec->pix_fmt;  
  367.         st->codec->frame_size     =  ic ->streams[videostream] ->codec->frame_size;  
  368.         st->codec->has_b_frames       =  ic ->streams[videostream] ->codec->has_b_frames;  
  369.         st->codec->extradata      =  ic ->streams[videostream] ->codec->extradata;  
  370.         st->codec->extradata_size =  ic ->streams[videostream] ->codec->extradata_size;  
  371.         st->codec->codec_tag      =  ic ->streams[videostream] ->codec->codec_tag;  
  372.         st->codec->bits_per_raw_sample        =  ic ->streams[videostream] ->codec->bits_per_raw_sample;  
  373.         st->codec->chroma_sample_location =  ic ->streams[videostream] ->codec->chroma_sample_location;  
  374.         st->time_base.den            =  ic ->streams[videostream] ->time_base.den;  
  375.         st->time_base.num            =  ic ->streams[videostream] ->time_base.num;  
  376.         st->cur_dts                  =  ic ->streams[videostream] ->cur_dts;  
  377.         st->stream_copy              =  1;  
  378.         st->pts.den                  =  ic ->streams[videostream] ->time_base.den;  
  379.         st->pts.num                  =  ic ->streams[videostream] ->time_base.num;  
  380.         if( oc ->oformat->flags & AVFMT_GLOBALHEADER)  
  381.             st ->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;  
  382.         if(av_q2d(ic ->streams[videostream] ->codec->time_base)*ic ->streams[videostream] ->codec->ticks_per_frame > av_q2d(ic ->streams[videostream]->time_base) &&   
  383.             av_q2d(ic ->streams[videostream]->time_base) < 1.0/1000)  
  384.         {  
  385.             st->codec->time_base = ic ->streams[videostream] ->codec->time_base;  
  386.             st->codec->time_base.num *= ic ->streams[videostream] ->codec->ticks_per_frame;  
  387.         }  
  388.         else  
  389.         {  
  390.             st->codec->time_base = ic ->streams[videostream] ->time_base;  
  391.         }  
  392.         st->disposition              =  ic ->streams[videostream] ->disposition;  
  393.     }  
  394.     if(audiostream >= 0 )  
  395.     {  
  396.         AVStream * st = av_new_stream( oc, audiostream);  
  397.         if(!st)  
  398.         {  
  399.             printf("can not add a audio stream.\n");  
  400.             return -4;  
  401.         }  
  402.         st->codec->codec_id           =  ic ->streams[audiostream] ->codec->codec_id;  
  403.         st->codec->codec_type     =  CODEC_TYPE_AUDIO;  
  404.         st->codec->bit_rate           =  ic ->streams[audiostream] ->codec->bit_rate;  
  405.         st->codec->gop_size           =  ic ->streams[audiostream] ->codec->gop_size;  
  406.         st->codec->pix_fmt            =  ic ->streams[audiostream] ->codec->pix_fmt;  
  407.         st->codec->bit_rate           =  ic ->streams[audiostream] ->codec->bit_rate;  
  408.         st->codec->channel_layout =  ic ->streams[audiostream] ->codec->channel_layout;  
  409.         st->codec->frame_size     =  ic ->streams[audiostream] ->codec->frame_size;  
  410.         st->codec->sample_rate        =  ic ->streams[audiostream] ->codec->sample_rate;  
  411.         st->codec->channels           =  ic ->streams[audiostream] ->codec->channels;      
  412.         st->codec->block_align        =  ic ->streams[audiostream] ->codec->block_align;   
  413.         st->time_base.den            =  ic ->streams[audiostream] ->time_base.den;  
  414.         st->time_base.num            =  ic ->streams[audiostream] ->time_base.num;  
  415.         st->stream_copy              =  1;  
  416.         st->pts.den                  =  ic ->streams[audiostream] ->time_base.den;  
  417.         st->pts.num                  =  ic ->streams[audiostream] ->time_base.num;  
  418.         if( oc->oformat->flags & AVFMT_GLOBALHEADER)  
  419.             st ->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;  
  420.         if(av_q2d(ic ->streams[audiostream] ->codec->time_base)*ic ->streams[audiostream] ->codec->ticks_per_frame > av_q2d(ic ->streams[audiostream]->time_base) &&   
  421.             av_q2d(ic ->streams[audiostream]->time_base) < 1.0/1000)  
  422.         {  
  423.             st->codec->time_base = ic ->streams[audiostream] ->codec->time_base;  
  424.             st->codec->time_base.num *= ic ->streams[audiostream] ->codec->ticks_per_frame;  
  425.         }  
  426.         else  
  427.         {  
  428.             st->codec->time_base = ic ->streams[audiostream] ->time_base;  
  429.         }  
  430.     }  
  431.     /* set the output parameters (must be done even if no parameters). */  
  432.     //AVFormatParameters params, *ap = ¶ms;   
  433.     //memset(ap, 0, sizeof(*ap));   
  434.     if (av_set_parameters(oc, NULL/*ap*/) < 0)  
  435.     {  
  436.         printf("invalid output format parameters.\n");  
  437.         return -5;  
  438.     }  
  439.     oc ->flags |= AVFMT_FLAG_NONBLOCK;  
  440.     /*******************************************init output contents end**********************************************************/  
  441.   
  442.     /* open the output file, if needed */  
  443.     if (!(oc ->oformat ->flags & AVFMT_NOFILE))   
  444.     {  
  445.         try  
  446.         {  
  447.             if (url_fopen(&oc->pb, ofile, URL_WRONLY) < 0)   
  448.             {  
  449.                 printf("Could not open file.\n");  
  450.                 return -6;  
  451.             }  
  452.         }  
  453.         catch(...)  
  454.         {  
  455.             printf("Could not open file.\n");  
  456.             return -6;  
  457.         }  
  458.     }  
  459.   
  460.     /* write the stream header, if any */  
  461.     if( 0 != av_write_header(oc))  
  462.     {  
  463.         printf("write the stream header failed.\n");  
  464.         return -7;  
  465.     }  
  466.   
  467.     return 0;  
  468. }