#include

ffmpeg API录制rtsp视频流

系统 1751 0

原文出自 http://blog.csdn.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. }  

ffmpeg API录制rtsp视频流


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论