extern "C"
{
#include "libavformat\avformat.h"
};
//将视频流和音频流封装成多媒体文件
void StreamToMedia(char *Path_I_V,char *Path_I_A,char *Path_O)
{
//结构体AVFormatContext -- 包含了多媒体流的格式内容
//打开、查找输入的视频流
AVFormatContext *pFormatContext_I_V = NULL;
if(avformat_open_input(&pFormatContext_I_V,Path_I_V,0,0) < 0)
goto end;
if(avformat_find_stream_info(pFormatContext_I_V,0) < 0)
goto end;
//打开、查找输入的音频流
AVFormatContext *pFormatContext_I_A = NULL;
if(avformat_open_input(&pFormatContext_I_A,Path_I_A,0,0) < 0)
goto end;
if(avformat_find_stream_info(pFormatContext_I_A,0) < 0)
goto end;
//初始化一个用于输出的结构体AVFormatContext,并猜测其输出数据的格式
AVFormatContext *pFormatContext_O = NULL;
avformat_alloc_output_context2(&pFormatContext_O,NULL,NULL,Path_O);
if(pFormatContext_O == NULL)
goto end;
//结构体AVOutputFormat -- 存储输出数据的封装格式
AVOutputFormat *pOutputFormat = NULL;
//struct AVOutputFormat *oformat -- 结构体AVFormatContext的参数
pOutputFormat = pFormatContext_O->oformat;
//获取视频流输入索引,创建对应输出视频流并设置其输出索引、编码器上下文等参数
int i = 0,VideoIndex_I = -1,VideoIndex_O = -1;
for(i=0;i<pFormatContext_I_V->nb_streams;i++)
{
if(pFormatContext_I_V->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
//获得视频流输入索引
VideoIndex_I = i;
//结构体AVStream -- 存储视频/音频流信息
AVStream *StreamIn = pFormatContext_I_V->streams[i];
//以输入的流所使用的编码器创建一条输出流,每次创建都会生成对应的新的索引
AVStream *StreamOut = avformat_new_stream(pFormatContext_O,StreamIn->codec->codec);
if(!StreamOut)
goto end;
//获取生成的输出多媒体流中视/音频流的索引
VideoIndex_O = StreamOut->index;
//将输入视频/音频的参数拷贝至输出视频/音频的AVCodecContext结构体
if(avcodec_copy_context(StreamOut->codec,StreamIn->codec) < 0)
goto end;
StreamOut->codec->codec_tag = 0;
if(pFormatContext_O->oformat->flags & AVFMT_GLOBALHEADER)
StreamOut->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
break;
}
}
//获取音频流输入索引,创建对应输出音频流并设置其输出索引、编码器上下文等参数
int AudioIndex_I = -1,AudioIndex_O = -1;
for(i=0;i<pFormatContext_I_A->nb_streams;i++)
{
if(pFormatContext_I_A->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
{
//获得音频流输入索引
AudioIndex_I = i;
AVStream *StreamIn = pFormatContext_I_A->streams[i];
AVStream *StreamOut = avformat_new_stream(pFormatContext_O,StreamIn->codec->codec);
if(!StreamOut)
goto end;
AudioIndex_O = StreamOut->index;
if(avcodec_copy_context(StreamOut->codec,StreamIn->codec) < 0)
goto end;
StreamOut->codec->codec_tag = 0;
if(pFormatContext_O->oformat->flags & AVFMT_GLOBALHEADER)
StreamOut->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
break;
}
}
//打开多媒体流输出文件
if(!(pOutputFormat->flags & AVFMT_NOFILE))
if(avio_open(&pFormatContext_O->pb,Path_O,AVIO_FLAG_WRITE) < 0)
goto end;
//写多媒体流输出文件的文件头
if(avformat_write_header(pFormatContext_O,NULL) < 0)
goto end;
//对于某些封装格式(例如MP4/FLV/MKV等)中的H.264,需要用到名称为“h264_mp4toannexb”的bitstream filter
AVBitStreamFilterContext* h264bsfc = av_bitstream_filter_init("h264_mp4toannexb");
//对于某些封装格式(例如MP4/FLV/MKV等)中的AAC,需要用到名称为“aac_adtstoasc”的bitstream filter
AVBitStreamFilterContext* aacbsfc = av_bitstream_filter_init("aac_adtstoasc");
//定义AVPacket数据缓存区
AVPacket pPacket;
//定义输出流每一帧数据在处理中的索引值,以处理时间戳
int StreamFrameIndex = 0;
int64_t ts_a = 0,ts_b = 0;
//循环写多媒体流输出文件的内容,直到写完为止
while(1)
{
AVStream *StreamIn,*StreamOut;
int StreamIndex = 0;
//av_compare_ts() -- 比较时间戳,决定写入视频还是写入音频
if(av_compare_ts(ts_a,pFormatContext_I_V->streams[VideoIndex_I]->time_base,ts_b,pFormatContext_I_A->streams[AudioIndex_I]->time_base) <= 0)
{
StreamIndex = VideoIndex_O;
//av_read_frame() -- 从输入流中取出相应流的AVPacket
if(av_read_frame(pFormatContext_I_V,&pPacket) >= 0)
{
do{
StreamIn = pFormatContext_I_V->streams[pPacket.stream_index];
StreamOut = pFormatContext_O->streams[VideoIndex_O];
//判断当前AVPacket数据是否为视频流
if(pPacket.stream_index == VideoIndex_I)
{
//如果当前AVPacket数据并无pts值,则运算求出
if(pPacket.pts == AV_NOPTS_VALUE)
{
//结构体AVRational -- 时间基本单位,在条件(以秒为单位)帧时间戳派代表出席了会议
AVRational TimeBase = StreamIn->time_base;
//计算两帧之间时长(单位微秒),如1秒25帧就会得出40000微秒
int64_t Duration = (double)AV_TIME_BASE/av_q2d(StreamIn->r_frame_rate);
//计算当前AVPacket数据的显示时间戳
pPacket.pts = (double)(StreamFrameIndex*Duration)/(double)(av_q2d(TimeBase)*AV_TIME_BASE);
//计算当前AVPacket数据的解码时间戳
pPacket.dts = pPacket.pts;
//计算当前AVPacket数据的时长
pPacket.duration=(double)Duration/(double)(av_q2d(TimeBase)*AV_TIME_BASE);
StreamFrameIndex++;
}
ts_a = pPacket.pts;
break;
}
}while(av_read_frame(pFormatContext_I_V,&pPacket) >= 0);
}
else
break;
}
else
{
StreamIndex = AudioIndex_O;
if(av_read_frame(pFormatContext_I_A,&pPacket) >= 0)
{
do{
StreamIn = pFormatContext_I_A->streams[pPacket.stream_index];
StreamOut = pFormatContext_O->streams[AudioIndex_O];
//判断当前AVPacket数据是否为音频流
if(pPacket.stream_index == AudioIndex_I)
{
if(pPacket.pts == AV_NOPTS_VALUE)
{
AVRational TimeBase = StreamIn->time_base;
int64_t Duration = (double)AV_TIME_BASE/av_q2d(StreamIn->r_frame_rate);
pPacket.pts = (double)(StreamFrameIndex*Duration)/(double)(av_q2d(TimeBase)*AV_TIME_BASE);
pPacket.dts = pPacket.pts;
pPacket.duration=(double)Duration/(double)(av_q2d(TimeBase)*AV_TIME_BASE);
StreamFrameIndex++;
}
ts_b = pPacket.pts;
break;
}
}while(av_read_frame(pFormatContext_I_A,&pPacket) >= 0);
}
else
break;
}
//使用filter转换
av_bitstream_filter_filter(h264bsfc,StreamOut->codec,NULL,&pPacket.data,&pPacket.size,pPacket.data,pPacket.size,0);
av_bitstream_filter_filter(aacbsfc,StreamOut->codec,NULL,&pPacket.data,&pPacket.size,pPacket.data,pPacket.size,0);
//int64_t pts -- 显示时间戳
pPacket.pts = av_rescale_q_rnd(pPacket.pts,StreamIn->time_base,StreamOut->time_base,(AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
//int64_t dts -- 解码时间戳
pPacket.dts = av_rescale_q_rnd(pPacket.dts,StreamIn->time_base,StreamOut->time_base,(AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
//int duration -- 数据的时长,以所属媒体流的时间基准为单位
pPacket.duration = av_rescale_q(pPacket.duration,StreamIn->time_base,StreamOut->time_base);
//int64_t pos -- 该数据在媒体流中的字节偏移量
pPacket.pos = -1;
//int stream_index -- 所属媒体流的索引
pPacket.stream_index = StreamIndex;
//写入一个AVPacket到输出文件
if(av_interleaved_write_frame(pFormatContext_O,&pPacket) < 0)
break;
//清空AVPacket结构体数据
av_free_packet(&pPacket);
}
//写多媒体流输出文件的文件尾
av_write_trailer(pFormatContext_O);
//关闭filter
av_bitstream_filter_close(h264bsfc);
av_bitstream_filter_close(aacbsfc);
end:
//资源释放
avio_close(pFormatContext_O->pb);
avformat_free_context(pFormatContext_O);
avformat_close_input(&pFormatContext_I_A);
avformat_close_input(&pFormatContext_I_V);
}
int main(int argc,char **argv)
{
//注册所有的文件格式和编解码器
av_register_all();
StreamToMedia("Video.h264","Audio.aac","Media.mp4");
return 0;
}
没有合适的资源?快使用搜索试试~ 我知道了~
FFmpeg视频、音频复用(VC2010)
共305个文件
h:162个
tlog:102个
lib:11个
3星 · 超过75%的资源 需积分: 11 63 下载量 9 浏览量
2015-07-03
16:30:18
上传
评论 1
收藏 18.16MB ZIP 举报
温馨提示
VC2010下,基于FFmpeg实现H264视频、AAC音频复用合成为MP4影音文件,因我的两个资源原本就是一个TS流中解出来的,所以复用后是影音同步的,注释详尽,表示感谢雷霄骅,因我做FFmpeg的项目过程中,用了不少他的代码,这个也是,不过我加入了完整的注释,便于其他人看懂,因我做了封装,朋友们可以直接拿去当函数用
资源推荐
资源详情
资源评论
收起资源包目录
FFmpeg视频、音频复用(VC2010) (305个子文件)
Audio.aac 350KB
FFmpeg.cpp 8KB
avcodec-56.dll 21.33MB
avformat-56.dll 5.73MB
avfilter-5.dll 2.28MB
avdevice-56.dll 1.32MB
SDL2.dll 984KB
avutil-54.dll 482KB
swscale-3.dll 442KB
swresample-1.dll 275KB
postproc-53.dll 129KB
FFmpeg.exe 33KB
FFmpeg.vcxproj.filters 955B
SDL_opengl.h 622KB
avcodec.h 178KB
SDL_opengles2.h 129KB
avformat.h 103KB
avfilter.h 56KB
SDL_haptic.h 38KB
opt.h 37KB
pixfmt.h 34KB
SDL_video.h 33KB
SDL_render.h 32KB
SDL_events.h 26KB
frame.h 24KB
avio.h 22KB
swresample.h 20KB
SDL_audio.h 20KB
SDL_hints.h 19KB
SDL_surface.h 18KB
intreadwrite.h 18KB
avdevice.h 18KB
SDL_pixels.h 15KB
SDL_scancode.h 15KB
pixdesc.h 15KB
SDL_keycode.h 14KB
mem.h 14KB
common.h 14KB
old_pix_fmts.h 14KB
SDL_stdinc.h 14KB
avstring.h 13KB
SDL_test_fuzzer.h 13KB
swscale.h 12KB
SDL_assert.h 10KB
log.h 10KB
old_codec_ids.h 10KB
SDL_gamecontroller.h 10KB
samplefmt.h 10KB
SDL_thread.h 10KB
buffer.h 10KB
channel_layout.h 9KB
SDL_atomic.h 9KB
avutil.h 8KB
imgutils.h 8KB
SDL_joystick.h 8KB
_mingw.h 8KB
vdpau.h 8KB
dict.h 8KB
bprint.h 8KB
parseutils.h 7KB
buffersink.h 7KB
SDL_mouse.h 7KB
SDL_rwops.h 7KB
SDL_syswm.h 7KB
SDL_system.h 7KB
SDL_mutex.h 7KB
version.h 6KB
SDL_keyboard.h 6KB
SDL_log.h 6KB
xvmc.h 6KB
SDL_endian.h 6KB
vda.h 6KB
stdint.h 6KB
inttypes.h 6KB
SDL_shape.h 6KB
SDL_config.h 5KB
error.h 5KB
SDL.h 5KB
timecode.h 5KB
eval.h 5KB
SDL_filesystem.h 5KB
mathematics.h 5KB
SDL_version.h 5KB
fifo.h 5KB
cpu.h 5KB
SDL_test_common.h 5KB
buffersrc.h 5KB
SDL_test_md5.h 5KB
SDL_messagebox.h 5KB
audio_fifo.h 4KB
SDL_main.h 4KB
SDL_platform.h 4KB
rational.h 4KB
SDL_test_harness.h 4KB
attributes.h 4KB
begin_code.h 4KB
SDL_rect.h 4KB
version.h 4KB
SDL_cpuinfo.h 4KB
vaapi.h 4KB
共 305 条
- 1
- 2
- 3
- 4
资源评论
- raoxu2016-07-05怎么都是视频流对视频流的,怎么没有图像数据存储成视频流的例子呢黄忻2016-08-24请看我其他的代码,有图像存储成视频的,比如将桌面进行录像的代码,还有是yuv视频帧序列存储为视频的等等
黄忻
- 粉丝: 28
- 资源: 111
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- 最新版新UI包天付费视频打赏程序 带包天+可扣量+代理+多模板非云赏V系列
- YOLO算法-检测驾驶员侧车窗是否关闭数据集-564张图像带标签-车窗关闭-汽车-车窗打开.zip
- YOLO算法-下水管道缺陷检测数据集-980张图像带标签-关节偏移-障碍物-裂纹-带扣-洞-公用设施入侵-碎片.zip
- YOLO算法-刀器数据集-610张图像带标签-刀.zip
- YOLO算法-办公室椅子数据集-876张图像带标签.zip
- YOLO算法-绵羊检测数据集-574张图像带标签-羊.zip
- YOLO算法-包装好的服装数据集-654张图像带标签-.zip
- YOLO算法-警车检测数据集-676张图像带标签-.zip
- YOLO算法-垃圾箱检测数据集-1228张图像带标签-垃圾桶.zip
- YOLO算法-刀具检测数据集-300张图像带标签-.zip
- G120 EPOS基本定位功能关键点系列-堆垛机报F7452追踪原因.mp4
- YOLO算法-罐头和瓶子数据集-595张图像带标签.zip
- YOLO算法-回收站数据集-501张图像带标签-黑色垃圾箱-绿色垃圾桶-箱子-杯子-老鼠-蓝色垃圾桶.zip
- 2015年10月及2016年4月全国高等教育自学考试试题及答案02325
- YOLO算法-刀数据集-830张图像带标签-刀.zip
- YOLO算法-雨水排放涵洞模型数据集-1000张图像带标签-.zip
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功