对于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等输入流音视频而且进行解码输出的更多相关文章

  1. 基于FFMPEG SDK流媒体开发1---解码媒体文件流信息

    近期项目涉及到流媒体等开发,因为有过开发经验深知其难度所在,没办法仅仅能又一次拾起,最新版的SDK被改的一塌糊涂,只是大体的开发思路都是一样的,看多少书查多少资料都无用,一步一步的编写代码 才是学好的 ...

  2. FFmpeg命令行工具和批处理脚本进行简单的音视频文件编辑

    FFmpeg_Tutorial FFmpeg工具和sdk库的使用demo 一.使用FFmpeg命令行工具和批处理脚本进行简单的音视频文件编辑 1.基本介绍 对于每一个从事音视频技术开发的工程师,想必没 ...

  3. android音视频点/直播模块开发

      音视频 版权声明:本文为博主原创文章,未经博主允许不得转载. 前言 随着音视频领域的火热,在很多领域(教育,游戏,娱乐,体育,跑步,餐饮,音乐等)尝试做音视频直播/点播功能,那么作为开发一个小白, ...

  4. Android 音视频开发学习思路

    Android 音视频开发这块目前的确没有比较系统的教程或者书籍,网上的博客文章也都是比较零散的.只能通过一点点的学习和积累把这块的知识串联积累起来. 初级入门篇: Android 音视频开发(一) ...

  5. Android音视频点/直播模块开发实践总结-zz

    随着音视频领域的火热,在很多领域(教育,游戏,娱乐,体育,跑步,餐饮,音乐等)尝试做音视频直播/点播功能.那么作为开发一个小白,如何快速学习音视频基础知识,了解音视频编解码的传输协议,编解码方式,以及 ...

  6. FFmpeg Android 学习(一):Android 如何调用 FFMPEG 编辑音视频

    一.概述 在Android开发中,我们对一些音视频的处理比较无力,特别是编辑音视频这部分.而且在Android上对视频编辑方面,几乎没有任何API做支持,MediaCodec(硬编码)也没有做支持.那 ...

  7. Python音视频开发:消除抖音短视频Logo和去电视台标

    ☞ ░ 前往老猿Python博文目录 ░ 一.引言 对于带Logo(如抖音Logo.电视台标)的视频,有三种方案进行Logo消除: 直接将对应区域用对应图像替换: 直接将对应区域模糊化: 通过变换将要 ...

  8. Moviepy音视频开发:视频转gif动画或jpg图片exe图形化工具开发案例

    ☞ ░ 前往老猿Python博文目录 ░ 一.引言 老猿之所以学习和研究Moviepy的使用,是因为需要一个将视频转成动画的工具,当时在网上到处搜索查找免费使用工具,结果找了很多自称免费的工具,但转完 ...

  9. moviepy音视频开发:使用credits1给视频加片头片尾字幕

    ☞ ░ 前往老猿Python博文目录 ░ 一.概述 在<moviepy音视频剪辑:视频基类VideoClip子类DataVideoClip.UpdatedVideoClip.ImageClip. ...

随机推荐

  1. UGUI 点击穿透问题

    unity上 用 做游戏欢迎界面上通用的ui,然后导到游戏里面直接用,但发现游戏里面是用ngui的,点击ugui 的ui 会穿透过去 ngui会响应,原本模型的点击处理也会响应 我用的 unity 版 ...

  2. 树上的路径 BZOJ 3784

    树上的路径 [问题描述] 给定一个N个结点的树,结点用正整数1..N编号.每条边有一个正整数权值.用d(a,b)表示从结点a到结点b路边上经过边的权值.其中要求a<b.将这n*(n-1)/2个距 ...

  3. Address already in use: AH00072: make_sock: could not bind to address 0.0.0.0:80

    ubuntu上安装Apache2时出现错误 Address already in use: AH00072: make_sock: could not bind to address 0.0.0.0: ...

  4. Linux 之 CentOS练习

    CentOS练习 参考教程:[千峰教育] 一.安装配置CentOS 1.安装虚拟机:VirtualBox. (1)软件下载:https://www.virtualbox.org/. (2)一路点击下一 ...

  5. hdu 1099(数学)

    Lottery Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Sub ...

  6. python 终端模拟模块 pexpect

    简单介绍pexpect是 Don Libes 的 Expect 语言的一个 Python 实现,是一个用来启动子程序,并使用正则表达式对程序输出做出特定响应,以此实现与其自动交互的 Python 模块 ...

  7. 扩展欧几里得算法(exGCD)学习笔记

    @(学习笔记)[扩展欧几里得] 本以为自己学过一次的知识不会那么容易忘记, 但事实证明, 两个星期后的我就已经不会做扩展欧几里得了...所以还是写一下学习笔记吧 问题概述 求解: \[ax + by ...

  8. Web地图服务、WMS 请求方式、网络地图服务(WMS)的三大操作

    转自奔跑的熊猫原文 Web地图服务.WMS 请求方式.网络地图服务(WMS)的三大操作 1.GeoServer(地理信息系统服务器) GeoServer是OpenGIS Web 服务器规范的 J2EE ...

  9. Android 震动 和 停止 代码

    <span style="font-size:18px;">MainActivity.java</span> package com.Utils.vibra ...

  10. tf.nn.softmax_cross_entropy_with_logits的用法

    http://blog.csdn.net/mao_xiao_feng/article/details/53382790 计算loss的时候,最常见的一句话就是tf.nn.softmax_cross_e ...