zoukankan      html  css  js  c++  java
  • ffmpeg API录制rtsp视频流

    原文出自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 != '')  
    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 == '' || *s2 == '')  
    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 ",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 write frame failed. ",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. ",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. ");  
    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. ");  
    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. ");  
    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. ");  
    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. ");  
    450.                 return -6;  
    451.             }  
    452.         }  
    453.         catch(...)  
    454.         {  
    455.             printf("Could not open file. ");  
    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. ");  
    464.         return -7;  
    465.     }  
    466.   
    467.     return 0;  
    468. }  
  • 相关阅读:
    移动端的头文件
    时间倒计时
    H5 判断应用是否打开或是下载
    创建 XMLHttpRequest 对象
    JS 发送POST
    总结题
    uploadify 插件,去了进度条
    PC 拖动 以百分比计算
    pc 拖动效果,拖动带范围
    spring.net 在demo中的分析
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3217619.html
Copyright © 2011-2022 走看看