• FFMPEG SDK流媒体开发2---分离.mp4等输入流音视频并且进行解码输出(转)


    对于FFMPEG SDK  提供的Demuxing 为我们实现多路复用  提供了很多方便,下面的案案例 实现的是 分离一个媒体文件的音频 视频流 并且解码输出 到  不同的文件中。

    对于音频被还原回了 PCM格式  对于视频 被还原成了 YUV420等原生 格式

    注意我用的FFMPEG SDK是最新版   API接口稍有改变。

    每天更新 博客 记录自己学习的点点滴滴,写完了 上班去奋斗

    1. #include "stdafx.h"  
    2. /************************************************************************/  
    3. /* 利用分流器分流MP4文件音视频并进行解码输出   
    4. Programmer小卫-USher 2014/12/17 
    5. /************************************************************************/  
    6. //打开  
    7. #define __STDC_FORMAT_MACROS  
    8. #ifdef _CPPRTTI   
    9. extern "C"  
    10. {  
    11. #endif  
    12. #include "libavutil/imgutils.h"    //图像工具   
    13. #include "libavutil/samplefmt.h"  // 音频样本格式  
    14. #include "libavutil/timestamp.h"  //时间戳工具可以 被用于调试和日志目的   
    15. #include "libavformat/avformat.h" //Main libavformat public API header  包含了libavf I/O和   Demuxing  和Muxing 库   
    16. #ifdef _CPPRTTI   
    17. };  
    18. #endif  
    19.   
    20. //音视频编码器上下文  
    21. static AVCodecContext *pVideoContext,*pAudioContext;  
    22. static FILE *fVideoFile,*fAudioFile;  //输出文件句柄  
    23. static AVStream *pStreamVideo,*pStreamAudio; //媒体流    
    24. static unsigned char * videoDstData[4];  //视频数据   
    25. static int videoLineSize[4]; //   
    26. static int videoBufferSize; //视频缓冲区大小   
    27. static AVFormatContext *pFormatCtx=NULL; //格式上下文  
    28. static AVFrame*pFrame=NULL ; //  
    29. static AVPacket pkt;  //解码媒体包  
    30. static int ret=0; //状态  
    31. static int gotFrame; //获取到的视频流  
    32. //音视频流的索引  
    33. static int videoStreamIndex,audioStreamIndex;  
    34. //解码媒体包  
    35. int indexFrameVideo=0;  
    36. static int decode_packet(int* gotFrame, int param2)  
    37. {  
    38.     int ret  = 0 ;  
    39.     //解码数据大小  
    40.     int decodedSize=pkt.size ;   
    41.     //初始化获取的数据帧为0  
    42.     *gotFrame=0;  
    43.     //如果是视频流那么 解包视频流    
    44.     if(pkt.stream_index==videoStreamIndex)  
    45.     {  
    46.         if((ret=avcodec_decode_video2(pVideoContext,pFrame,gotFrame,&pkt))<0)  
    47.         {    
    48.             //解码视频帧失败  
    49.             return ret ;  
    50.         }  
    51.         indexFrameVideo++;  
    52.       
    53.           
    54.         //copy 解压后的数据到我们分配的空间中  
    55.         if(*gotFrame)  
    56.         {  
    57.             av_image_copy(videoDstData,videoLineSize, (const uint8_t **)(pFrame->data), pFrame->linesize,pVideoContext->pix_fmt, pVideoContext->width, pVideoContext->height);  
    58.             //写入数据到缓冲区  
    59.             fwrite(videoDstData[0], 1, videoBufferSize, fVideoFile);  
    60.             printf("输出当前第%d帧,大小:%d ",indexFrameVideo,videoBufferSize);  
    61.         }else  
    62.         {  
    63.             printf("第%d帧,丢失 ",indexFrameVideo);  
    64.         }  
    65.     }  
    66.     //音频流解包  
    67.     else if(pkt.stream_index==audioStreamIndex)  
    68.     {    
    69.         //解码音频信息  
    70.         if((ret=avcodec_decode_audio4(pAudioContext,pFrame,gotFrame,&pkt))<0)  
    71.             return ret ;  
    72.         decodedSize = FFMIN(ret, pkt.size);  
    73.         //算出当前帧的大小  
    74.         size_t unpadded_linesize = pFrame->nb_samples * av_get_bytes_per_sample((AVSampleFormat)pFrame->format);   
    75.         ///写入数据到音频文件  
    76.         fwrite(pFrame->extended_data[0], 1, unpadded_linesize, fAudioFile);     
    77.     }   
    78.     //取消所有引用  并且重置frame字段  
    79.     av_frame_unref(pFrame);  
    80.     return decodedSize ;  
    81. }  
    82.   
    83. ///根据样本格式 提示样本信息  
    84. static int get_format_from_sample_fmt(const char **fmt,  
    85.     enum AVSampleFormat sample_fmt)  
    86. {  
    87.     int i;  
    88.     struct sample_fmt_entry   
    89.     {  
    90.         enum AVSampleFormat sample_fmt;  
    91.         const char *fmt_be, *fmt_le;  
    92.     } sample_fmt_entries[] =   
    93.     {  
    94.         { AV_SAMPLE_FMT_U8, "u8", "u8" },  
    95.         { AV_SAMPLE_FMT_S16, "s16be", "s16le" },  
    96.         { AV_SAMPLE_FMT_S32, "s32be", "s32le" },  
    97.         { AV_SAMPLE_FMT_FLT, "f32be", "f32le" },  
    98.         { AV_SAMPLE_FMT_DBL, "f64be", "f64le" },  
    99.     };  
    100.     *fmt = NULL;  
    101.     for (i = 0; i < FF_ARRAY_ELEMS(sample_fmt_entries); i++)   
    102.     {  
    103.         struct sample_fmt_entry *entry = &sample_fmt_entries[i];  
    104.         if (sample_fmt == entry->sample_fmt) {  
    105.             *fmt = AV_NE(entry->fmt_be, entry->fmt_le);  
    106.             return 0;  
    107.         }  
    108.     }  
    109.     fprintf(stderr,"sample format %s is not supported as output format ",av_get_sample_fmt_name(sample_fmt));  
    110.     return -1;  
    111. }  
    112. int _tmain(int argc,char*argv[])  
    113. {     
    114.     if(argc<4)  
    115.     {  
    116.         printf("Parameter Error! ");  
    117.         return 0;  
    118.     }  
    119.   
    120.     //注册所有混流器 过滤器  
    121.     av_register_all();  
    122.     //注册所有编码器  
    123.     avcodec_register_all();  
    124.     //媒体输入源头  
    125.     char*pInputFile=argv[1];  
    126.     //视频输出文件  
    127.     char*pOutputVideoFile=argv[2];  
    128.     //音频输出文件  
    129.     char*pOutputAudioFile=argv[3];  
    130.     //分配环境上下文  
    131.     pFormatCtx=avformat_alloc_context() ;   
    132.     //打开输入源  并且读取输入源的头部  
    133.     if(avformat_open_input(&pFormatCtx,pInputFile,NULL,NULL)<0)  
    134.     {    
    135.         printf("Open Input Error! ");  
    136.         return 0 ;  
    137.     }  
    138.     //获取流媒体信息  
    139.     if(avformat_find_stream_info(pFormatCtx,NULL)<0)  
    140.     {  
    141.         printf("获取流媒体信息失败! ");  
    142.         return 0;   
    143.     }  
    144.     //打印媒体信息  
    145.     av_dump_format(pFormatCtx,0,pInputFile,0);  
    146.     for(unsigned i=0;i<pFormatCtx->nb_streams;i++)  
    147.     {     
    148.         AVStream *pStream=pFormatCtx->streams[i];  
    149.         AVMediaType mediaType=pStream->codec->codec_type;    
    150.         //提取不同的编解码器  
    151.         if(mediaType==AVMEDIA_TYPE_VIDEO)  
    152.         {    
    153.             videoStreamIndex=i ;  
    154.             pVideoContext=pStream->codec;  
    155.             pStreamVideo=pStream;  
    156.             fVideoFile=fopen(pOutputVideoFile,"wb");  
    157.             if(!fVideoFile)  
    158.             {    
    159.                 printf("con't open file! ");  
    160.                 goto end;  
    161.             }  
    162.   
    163.             int ret=av_image_alloc(videoDstData,videoLineSize,pVideoContext->width,pVideoContext->height,pVideoContext->pix_fmt,1);  
    164.             if(ret<0)  
    165.             {  
    166.                 printf("Alloc video buffer error! ");  
    167.                 goto end ;  
    168.             }  
    169.             videoBufferSize=ret ;  
    170.         }  
    171.         else if(mediaType==AVMEDIA_TYPE_AUDIO)  
    172.         {     
    173.             audioStreamIndex=i;  
    174.             pAudioContext=pStream->codec ;  
    175.             pStreamAudio=pStream;  
    176.             fAudioFile=fopen(pOutputAudioFile,"wb");  
    177.             if(!fAudioFile)  
    178.             {    
    179.                 printf("con't open file! ");  
    180.                 goto end;  
    181.             }  
    182.             //分配视频帧  
    183.             pFrame=av_frame_alloc();  
    184.             if(pFrame==NULL)  
    185.             {     
    186.                 av_freep(&videoDstData[0]);  
    187.                 printf("alloc audio frame error ");  
    188.                 goto end ;  
    189.             }  
    190.         }  
    191.         AVCodec *dec;  
    192.         //根据编码器id查找编码器  
    193.         dec=avcodec_find_decoder(pStream->codec->codec_id);  
    194.         if(dec==NULL)  
    195.         {     
    196.             printf("查找编码器失败! ");  
    197.             goto end;  
    198.         }  
    199.         if(avcodec_open2(pStream->codec, dec, nullptr)!=0)  
    200.         {  
    201.             printf("打开编码器失败! ");  
    202.             goto end;  
    203.         }  
    204.   
    205.     }  
    206.     av_init_packet(&pkt);  
    207.     pkt.data=NULL;  
    208.     pkt.size=0;  
    209.   
    210.     //读取媒体数据包  数据要大于等于0  
    211.     while(av_read_frame(pFormatCtx,&pkt)>=0)  
    212.     {    
    213.         AVPacket oriPkt=pkt ;  
    214.         do  
    215.         {     
    216.             //返回每个包解码的数据  
    217.             ret=decode_packet(&gotFrame,0);  
    218.             if(ret<0)  
    219.                 break;  
    220.             //指针后移  空闲内存减少  
    221.             pkt.data+=ret ;  
    222.             pkt.size-=ret ;  
    223.             //  
    224.         }while(pkt.size>0);  
    225.         //释放之前分配的空间  读取完毕必须释放包  
    226.         av_free_packet(&oriPkt);  
    227.     }  
    228.   
    229. end:  
    230.     //关闭视频编码器  
    231.     avcodec_close(pVideoContext);  
    232.     //关闭音频编码器  
    233.     avcodec_close(pAudioContext);  
    234.     avformat_close_input(&pFormatCtx);  
    235.     fclose(fVideoFile);  
    236.     fclose(fAudioFile);  
    237.     //释放编码帧  
    238.     avcodec_free_frame(&pFrame);  
    239.     //释放视频数据区  
    240.     av_free(videoDstData[0]);  
    241.     return  0;  
    242. }  
    243. 程序运行如下图所示   

    我们发现 MP4文件 被分离开了。。。

  • 相关阅读:
    【XSY2166】Hope 分治 FFT
    【XSY2612】Comb Avoiding Trees 生成函数 多项式求逆 矩阵快速幂
    【BZOJ1578】【USACO2009Feb】股票市场 背包DP
    【BZOJ2333】【SCOI2011】棘手的操作 treap合并
    【BZOJ1580】【USACO2009Hol】杀手游戏 计算几何
    【BZOJ3379】【USACO2004】交作业 区间DP
    【BZOJ2208】【JSOI2010】连通数 传递闭包
    【BZOJ4033】【HAOI2015】树上染色 树形DP
    【BZOJ3816】【清华集训2014】矩阵变换 稳定婚姻问题
    【XSY2528】道路建设 LCT 可持久化线段树
  • 原文地址:https://www.cnblogs.com/ting5/p/5069391.html
Copyright © 2020-2023  润新知