FFMPEG SDK流媒体开发2---分离.mp4等输入流音视频而且进行解码输出
对于FFMPEG SDK 提供的Demuxing 为我们实现多路复用 提供了非常多方便,以下的案案例 实现的是 分离一个媒体文件的音频 视频流 而且解码输出 到 不同的文件里。
对于音频被还原回了 PCM格式 对于视频 被还原成了 YUV420等原生 格式
注意我用的FFMPEG SDK是最新版 API接口稍有改变。
每天更新 博客 记录自己学习的点点滴滴,写完了 上班去
- #include "stdafx.h"
- /************************************************************************/
- /* 利用分流器分流MP4文件音视频并进行解码输出
- Programmer小卫-USher 2014/12/17
- /************************************************************************/
- //打开
- #define __STDC_FORMAT_MACROS
- #ifdef _CPPRTTI
- extern "C"
- {
- #endif
- #include "libavutil/imgutils.h" //图像工具
- #include "libavutil/samplefmt.h" // 音频样本格式
- #include "libavutil/timestamp.h" //时间戳工具能够 被用于调试和日志目的
- #include "libavformat/avformat.h" //Main libavformat public API header 包括了libavf I/O和 Demuxing 和Muxing 库
- #ifdef _CPPRTTI
- };
- #endif
- //音视频编码器上下文
- static AVCodecContext *pVideoContext,*pAudioContext;
- static FILE *fVideoFile,*fAudioFile; //输出文件句柄
- static AVStream *pStreamVideo,*pStreamAudio; //媒体流
- static unsigned char * videoDstData[4]; //视频数据
- static int videoLineSize[4]; //
- static int videoBufferSize; //视频缓冲区大小
- static AVFormatContext *pFormatCtx=NULL; //格式上下文
- static AVFrame*pFrame=NULL ; //
- static AVPacket pkt; //解码媒体包
- static int ret=0; //状态
- static int gotFrame; //获取到的视频流
- //音视频流的索引
- static int videoStreamIndex,audioStreamIndex;
- //解码媒体包
- int indexFrameVideo=0;
- static int decode_packet(int* gotFrame, int param2)
- {
- int ret = 0 ;
- //解码数据大小
- int decodedSize=pkt.size ;
- //初始化获取的数据帧为0
- *gotFrame=0;
- //假设是视频流那么 解包视频流
- if(pkt.stream_index==videoStreamIndex)
- {
- if((ret=avcodec_decode_video2(pVideoContext,pFrame,gotFrame,&pkt))<0)
- {
- //解码视频帧失败
- return ret ;
- }
- indexFrameVideo++;
- //copy 解压后的数据到我们分配的空间中
- if(*gotFrame)
- {
- av_image_copy(videoDstData,videoLineSize, (const uint8_t **)(pFrame->data), pFrame->linesize,pVideoContext->pix_fmt, pVideoContext->width, pVideoContext->height);
- //写入数据到缓冲区
- fwrite(videoDstData[0], 1, videoBufferSize, fVideoFile);
- printf("输出当前第%d帧,大小:%d\n",indexFrameVideo,videoBufferSize);
- }else
- {
- printf("第%d帧,丢失\n",indexFrameVideo);
- }
- }
- //音频流解包
- else if(pkt.stream_index==audioStreamIndex)
- {
- //解码音频信息
- if((ret=avcodec_decode_audio4(pAudioContext,pFrame,gotFrame,&pkt))<0)
- return ret ;
- decodedSize = FFMIN(ret, pkt.size);
- //算出当前帧的大小
- size_t unpadded_linesize = pFrame->nb_samples * av_get_bytes_per_sample((AVSampleFormat)pFrame->format);
- ///写入数据到音频文件
- fwrite(pFrame->extended_data[0], 1, unpadded_linesize, fAudioFile);
- }
- //取消全部引用 而且重置frame字段
- av_frame_unref(pFrame);
- return decodedSize ;
- }
- ///依据样本格式 提示样本信息
- static int get_format_from_sample_fmt(const char **fmt,
- enum AVSampleFormat sample_fmt)
- {
- int i;
- struct sample_fmt_entry
- {
- enum AVSampleFormat sample_fmt;
- const char *fmt_be, *fmt_le;
- } sample_fmt_entries[] =
- {
- { AV_SAMPLE_FMT_U8, "u8", "u8" },
- { AV_SAMPLE_FMT_S16, "s16be", "s16le" },
- { AV_SAMPLE_FMT_S32, "s32be", "s32le" },
- { AV_SAMPLE_FMT_FLT, "f32be", "f32le" },
- { AV_SAMPLE_FMT_DBL, "f64be", "f64le" },
- };
- *fmt = NULL;
- for (i = 0; i < FF_ARRAY_ELEMS(sample_fmt_entries); i++)
- {
- struct sample_fmt_entry *entry = &sample_fmt_entries[i];
- if (sample_fmt == entry->sample_fmt) {
- *fmt = AV_NE(entry->fmt_be, entry->fmt_le);
- return 0;
- }
- }
- fprintf(stderr,"sample format %s is not supported as output format\n",av_get_sample_fmt_name(sample_fmt));
- return -1;
- }
- int _tmain(int argc,char*argv[])
- {
- if(argc<4)
- {
- printf("Parameter Error!\n");
- return 0;
- }
- //注冊全部混流器 过滤器
- av_register_all();
- //注冊全部编码器
- avcodec_register_all();
- //媒体输入源头
- char*pInputFile=argv[1];
- //视频输出文件
- char*pOutputVideoFile=argv[2];
- //音频输出文件
- char*pOutputAudioFile=argv[3];
- //分配环境上下文
- pFormatCtx=avformat_alloc_context() ;
- //打开输入源 而且读取输入源的头部
- if(avformat_open_input(&pFormatCtx,pInputFile,NULL,NULL)<0)
- {
- printf("Open Input Error!\n");
- return 0 ;
- }
- //获取流媒体信息
- if(avformat_find_stream_info(pFormatCtx,NULL)<0)
- {
- printf("获取流媒体信息失败!\n");
- return 0;
- }
- //打印媒体信息
- av_dump_format(pFormatCtx,0,pInputFile,0);
- for(unsigned i=0;i<pFormatCtx->nb_streams;i++)
- {
- AVStream *pStream=pFormatCtx->streams[i];
- AVMediaType mediaType=pStream->codec->codec_type;
- //提取不同的编解码器
- if(mediaType==AVMEDIA_TYPE_VIDEO)
- {
- videoStreamIndex=i ;
- pVideoContext=pStream->codec;
- pStreamVideo=pStream;
- fVideoFile=fopen(pOutputVideoFile,"wb");
- if(!fVideoFile)
- {
- printf("con't open file!\n");
- goto end;
- }
- int ret=av_image_alloc(videoDstData,videoLineSize,pVideoContext->width,pVideoContext->height,pVideoContext->pix_fmt,1);
- if(ret<0)
- {
- printf("Alloc video buffer error!\n");
- goto end ;
- }
- videoBufferSize=ret ;
- }
- else if(mediaType==AVMEDIA_TYPE_AUDIO)
- {
- audioStreamIndex=i;
- pAudioContext=pStream->codec ;
- pStreamAudio=pStream;
- fAudioFile=fopen(pOutputAudioFile,"wb");
- if(!fAudioFile)
- {
- printf("con't open file!\n");
- goto end;
- }
- //分配视频帧
- pFrame=av_frame_alloc();
- if(pFrame==NULL)
- {
- av_freep(&videoDstData[0]);
- printf("alloc audio frame error\n");
- goto end ;
- }
- }
- AVCodec *dec;
- //依据编码器id查找编码器
- dec=avcodec_find_decoder(pStream->codec->codec_id);
- if(dec==NULL)
- {
- printf("查找编码器失败!\n");
- goto end;
- }
- if(avcodec_open2(pStream->codec, dec, nullptr)!=0)
- {
- printf("打开编码器失败!\n");
- goto end;
- }
- }
- av_init_packet(&pkt);
- pkt.data=NULL;
- pkt.size=0;
- //读取媒体数据包 数据要大于等于0
- while(av_read_frame(pFormatCtx,&pkt)>=0)
- {
- AVPacket oriPkt=pkt ;
- do
- {
- //返回每一个包解码的数据
- ret=decode_packet(&gotFrame,0);
- if(ret<0)
- break;
- //指针后移 空暇内存降低
- pkt.data+=ret ;
- pkt.size-=ret ;
- //
- }while(pkt.size>0);
- //释放之前分配的空间 读取完成必须释放包
- av_free_packet(&oriPkt);
- }
- end:
- //关闭视频编码器
- avcodec_close(pVideoContext);
- //关闭音频编码器
- avcodec_close(pAudioContext);
- avformat_close_input(&pFormatCtx);
- fclose(fVideoFile);
- fclose(fAudioFile);
- //释放编码帧
- avcodec_free_frame(&pFrame);
- //释放视频数据区
- av_free(videoDstData[0]);
- return 0;
- }
- 程序执行例如以下图所看到的
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveXVlNzYwMzgzNQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
我们发现 MP4文件 被分离开了。
。。
FFMPEG SDK流媒体开发2---分离.mp4等输入流音视频而且进行解码输出的更多相关文章
- 基于FFMPEG SDK流媒体开发1---解码媒体文件流信息
近期项目涉及到流媒体等开发,因为有过开发经验深知其难度所在,没办法仅仅能又一次拾起,最新版的SDK被改的一塌糊涂,只是大体的开发思路都是一样的,看多少书查多少资料都无用,一步一步的编写代码 才是学好的 ...
- FFmpeg命令行工具和批处理脚本进行简单的音视频文件编辑
FFmpeg_Tutorial FFmpeg工具和sdk库的使用demo 一.使用FFmpeg命令行工具和批处理脚本进行简单的音视频文件编辑 1.基本介绍 对于每一个从事音视频技术开发的工程师,想必没 ...
- android音视频点/直播模块开发
音视频 版权声明:本文为博主原创文章,未经博主允许不得转载. 前言 随着音视频领域的火热,在很多领域(教育,游戏,娱乐,体育,跑步,餐饮,音乐等)尝试做音视频直播/点播功能,那么作为开发一个小白, ...
- Android 音视频开发学习思路
Android 音视频开发这块目前的确没有比较系统的教程或者书籍,网上的博客文章也都是比较零散的.只能通过一点点的学习和积累把这块的知识串联积累起来. 初级入门篇: Android 音视频开发(一) ...
- Android音视频点/直播模块开发实践总结-zz
随着音视频领域的火热,在很多领域(教育,游戏,娱乐,体育,跑步,餐饮,音乐等)尝试做音视频直播/点播功能.那么作为开发一个小白,如何快速学习音视频基础知识,了解音视频编解码的传输协议,编解码方式,以及 ...
- FFmpeg Android 学习(一):Android 如何调用 FFMPEG 编辑音视频
一.概述 在Android开发中,我们对一些音视频的处理比较无力,特别是编辑音视频这部分.而且在Android上对视频编辑方面,几乎没有任何API做支持,MediaCodec(硬编码)也没有做支持.那 ...
- Python音视频开发:消除抖音短视频Logo和去电视台标
☞ ░ 前往老猿Python博文目录 ░ 一.引言 对于带Logo(如抖音Logo.电视台标)的视频,有三种方案进行Logo消除: 直接将对应区域用对应图像替换: 直接将对应区域模糊化: 通过变换将要 ...
- Moviepy音视频开发:视频转gif动画或jpg图片exe图形化工具开发案例
☞ ░ 前往老猿Python博文目录 ░ 一.引言 老猿之所以学习和研究Moviepy的使用,是因为需要一个将视频转成动画的工具,当时在网上到处搜索查找免费使用工具,结果找了很多自称免费的工具,但转完 ...
- moviepy音视频开发:使用credits1给视频加片头片尾字幕
☞ ░ 前往老猿Python博文目录 ░ 一.概述 在<moviepy音视频剪辑:视频基类VideoClip子类DataVideoClip.UpdatedVideoClip.ImageClip. ...
随机推荐
- 一款手机端的日历插件ICalendar.js
我的网盘:http://pan.baidu.com/s/1jIib2Ay
- Z-Order(转)
原文转自 http://www.th7.cn/system/win/201406/60715.shtml 窗口在子窗口链中的先后顺序也就是窗口在屏幕上显示时的前后顺序,在子窗口链里位置越靠前的窗口显示 ...
- 标准C程序设计七---61
Linux应用 编程深入 语言编程 标准C程序设计七---经典C11程序设计 以下内容为阅读: <标准C程序设计>(第7版) 作者 ...
- 不同狀況下的 bq25896 register
no charger時的 bq25896 register [bq25890 reg@] [0x0]=0x7f [0x1]=0x6 [0x2]=0x91 [0x3]=0x1a [0x4]=0x8 [0 ...
- Day 17 编码+文本编辑+函数
知识点篇: #! /usr/bin/env python # -*- coding: utf-8 -*- # __author__ = "DaChao" # Date: 2017/ ...
- Scrollview总结:滑动问题、监听Scrollview实现头部局改变
ScrollView就是一个可以滚动的View,这个滚动的方向是垂直方向的,而HorizontalScrollView则是一个水平方向的可以滚动的View. ScrollView的简单介绍 Scrol ...
- 深入理解js中的立即执行函数(function(){…})()
javascript和其他编程语言相比比较随意,所以javascript代码中充满各种奇葩的写法,有时雾里看花,当然,能理解各型各色的写法也是对javascript语言特性更进一步的深入理解. ( f ...
- 总结下web开发中基础性的常识
一,HTML/5 1,浏览器渲染过程 主流浏览器渲染过程叫法有区别,但是主要流程还是相同的.Gecko 将视觉格式化元素组成的树称为“框架树”.每个元素都是一个框架.WebKit 使用的术语是“呈现树 ...
- Software Engineering | Factory method pattern
工厂对象通常包含一个或多个方法,用来创建这个工厂所能创建的各种类型的对象.这些方法可能接收参数,用来指定对象创建的方式,最后返回创建的对象. 有时,特定类型对象的控制过程比简单地创建一个对象更复杂.在 ...
- Codeforces Round #321 (Div. 2) Kefa and Park 深搜
原题链接: 题意: 给你一棵有根树,某些节点的权值是1,其他的是0,问你从根到叶子节点的权值和不超过m的路径有多少条. 题解: 直接dfs一下就好了. 代码: #include<iostream ...