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\n",indexFrameVideo,videoBufferSize);  
  61.         }else  
  62.         {  
  63.             printf("第%d帧,丢失\n",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\n",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!\n");  
  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!\n");  
  136.         return 0 ;  
  137.     }  
  138.     //获取流媒体信息  
  139.     if(avformat_find_stream_info(pFormatCtx,NULL)<0)  
  140.     {  
  141.         printf("获取流媒体信息失败!\n");  
  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!\n");  
  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!\n");  
  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!\n");  
  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\n");  
  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("查找编码器失败!\n");  
  197.             goto end;  
  198.         }  
  199.         if(avcodec_open2(pStream->codec, dec, nullptr)!=0)  
  200.         {  
  201.             printf("打开编码器失败!\n");  
  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文件 被分离开了。。。

posted @ 2015-12-23 11:42  彩虹下的约定  阅读(321)  评论(0编辑  收藏  举报