最简单的基于FFMPEG的封装格式转换器(无编解码)
上图例举了一个举例:FLV(视频:H.264,音频:AAC)转码为AVI(视频:MPEG2,音频MP3)的样例。可见视频转码的过程通俗地讲相当于把视频和音频又一次“录”了一遍。
本程序的工作原理例如以下图所看到的:
由图可见,本程序并不进行视频和音频的编解码工作,因此本程序和普通的转码软件相比,有以下两个特点:
处理速度极快。视音频编解码算法十分复杂,占领了转码的绝大部分时间。由于不须要进行视音频的编码和解码,所以节约了大量的时间。
视音频质量无损。由于不须要进行视音频的编码和解码,所以不会有视音频的压缩损伤。
以下贴上代码,代码是从FFmpeg的样例改编的,平台是VC2010。
/*
*最简单的基于FFmpeg的封装格式转换器
*Simplest FFmpeg Remuxer
*
*雷霄骅 Lei Xiaohua
*leixiaohua1020@126.com
*中国传媒大学/数字电视技术
*Communication University of China / Digital TV Technology
*http://blog.csdn.net/leixiaohua1020
*
*本程序实现了视频封装格式之间的转换。
*须要注意的是本程序并不改变视音频的编码格式。
*
* This software converts a media file from one container format
* to another container format without encoding/decoding video files.
*/
#include "stdafx.h"
extern "C"
{
#include "libavformat/avformat.h"
};
int _tmain(int argc, _TCHAR* argv[])
{
AVOutputFormat *ofmt = NULL;
//输入相应一个AVFormatContext,输出相应一个AVFormatContext
//(Input AVFormatContext and Output AVFormatContext)
AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
AVPacket pkt;
const char *in_filename, *out_filename;
int ret, i;
if (argc < 3) {
printf("usage: %s input output\n"
"Remux a media file with libavformat and libavcodec.\n"
"The output format is guessed according to the file extension.\n"
"Modified by Lei Xiaohua, leixiaohua1020@126.com\n"
"Communication University of China / Digital TV Technology\n"
"http://blog.csdn.net/leixiaohua1020", argv[0]);
return 1;
}
in_filename = argv[1];//输入文件名称(Input file URL)
out_filename = argv[2];//输出文件名称(Output file URL)
av_register_all();
//输入(Input)
if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
printf( "Could not open input file.");
goto end;
}
if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
printf( "Failed to retrieve input stream information");
goto end;
}
av_dump_format(ifmt_ctx, 0, in_filename, 0);
//输出(Output)
avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);
if (!ofmt_ctx) {
printf( "Could not create output context\n");
ret = AVERROR_UNKNOWN;
goto end;
}
ofmt = ofmt_ctx->oformat;
for (i = 0; i < ifmt_ctx->nb_streams; i++) {
//依据输入流创建输出流(Create output AVStream according to input AVStream)
AVStream *in_stream = ifmt_ctx->streams[i];
AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);
if (!out_stream) {
printf( "Failed allocating output stream\n");
ret = AVERROR_UNKNOWN;
goto end;
}
//复制AVCodecContext的设置(Copy the settings of AVCodecContext)
ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
if (ret < 0) {
printf( "Failed to copy context from input to output stream codec context\n");
goto end;
}
out_stream->codec->codec_tag = 0;
if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
//输出一下格式------------------
av_dump_format(ofmt_ctx, 0, out_filename, 1);
//打开输出文件(Open output file)
if (!(ofmt->flags & AVFMT_NOFILE)) {
ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
if (ret < 0) {
printf( "Could not open output file '%s'", out_filename);
goto end;
}
}
//写文件头(Write file header)
ret = avformat_write_header(ofmt_ctx, NULL);
if (ret < 0) {
printf( "Error occurred when opening output file\n");
goto end;
}
int frame_index=0;
while (1) {
AVStream *in_stream, *out_stream;
//获取一个AVPacket(Get an AVPacket)
ret = av_read_frame(ifmt_ctx, &pkt);
if (ret < 0)
break;
in_stream = ifmt_ctx->streams[pkt.stream_index];
out_stream = ofmt_ctx->streams[pkt.stream_index];
/* copy packet */
//转换PTS/DTS(Convert PTS/DTS)
pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
pkt.pos = -1;
//写入(Write)
ret = av_interleaved_write_frame(ofmt_ctx, &pkt);
if (ret < 0) {
printf( "Error muxing packet\n");
break;
}
printf("Write %8d frames to output file\n",frame_index);
av_free_packet(&pkt);
frame_index++;
}
//写文件尾(Write file trailer)
av_write_trailer(ofmt_ctx);
end:
avformat_close_input(&ifmt_ctx);
/* close output */
if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
avio_close(ofmt_ctx->pb);
avformat_free_context(ofmt_ctx);
if (ret < 0 && ret != AVERROR_EOF) {
printf( "Error occurred.\n");
return -1;
}
return 0;
}
调试的时候,仅仅须要“右键project->调试->命令行參数”里面设置输入的文件名称和输出的文件名称就能够了。
下图显示了一个測试的输入文件的视音频參数。
下图显示了输出文件的视音频參数。能够看出除了视频的封装格式从flv转换成了mp4,其它有关视音频编码的參数没有不论什么变化。
完整project下载地址:
最简单的基于FFMPEG的封装格式转换器(无编解码)的更多相关文章
- 最简单的基于FFmpeg的封装格式处理:视音频分离器简化版(demuxer-simple)
===================================================== 最简单的基于FFmpeg的封装格式处理系列文章列表: 最简单的基于FFmpeg的封装格式处理 ...
- 最简单的基于FFmpeg的封装格式处理:视音频复用器(muxer)
===================================================== 最简单的基于FFmpeg的封装格式处理系列文章列表: 最简单的基于FFmpeg的封装格式处理 ...
- 最简单的基于FFmpeg的封装格式处理:视音频分离器(demuxer)
===================================================== 最简单的基于FFmpeg的封装格式处理系列文章列表: 最简单的基于FFmpeg的封装格式处理 ...
- 最简单的基于FFmpeg的推流器(以推送RTMP为例)
===================================================== 最简单的基于FFmpeg的推流器系列文章列表: <最简单的基于FFmpeg的推流器(以 ...
- 最简单的基于FFMPEG的转码程序
本文介绍一个简单的基于FFmpeg的转码器.它可以将一种视频格式(包括封转格式和编码格式)转换为另一种视频格式.转码器在视音频编解码处理的程序中,属于一个比较复杂的东西.因为它结合了视频的解码和编码. ...
- 最简单的基于FFMPEG的音频编码器(PCM编码为AAC)
http://blog.csdn.net/leixiaohua1020/article/details/25430449 本文介绍一个最简单的基于FFMPEG的音频编码器.该编码器实现了PCM音频采样 ...
- 最简单的基于FFMPEG的视频编码器(YUV编码为H.264)
本文介绍一个最简单的基于FFMPEG的视频编码器.该编码器实现了YUV420P的像素数据编码为H.264的压缩编码数据.编码器代码十分简单,可是每一行代码都非常重要,适合好好研究一下.弄清楚了本代码也 ...
- 最简单的基于FFMPEG+SDL的视频播放器 ver2 (採用SDL2.0)
===================================================== 最简单的基于FFmpeg的视频播放器系列文章列表: 100行代码实现最简单的基于FFMPEG ...
- 最简单的基于FFmpeg的解码器-纯净版(不包含libavformat)
===================================================== 最简单的基于FFmpeg的视频播放器系列文章列表: 100行代码实现最简单的基于FFMPEG ...
随机推荐
- javax.servlet不存在的问题
摘自:http://blog.csdn.net/tgeh23/article/details/2216682 最近在学习servlet,看书看的似乎还比较理想就想上机试下,这一试就发现,问题来 ...
- Swift开发之 ---- Swift宏定义
swift中没有了#Define这种宏定义了,可以用let来声明常量来取代,判断当前系统版本 let IS_IOS7 = (UIDevice.currentDevice().systemVersion ...
- 从零到一:caffe-windows(CPU)配置与利用mnist数据集训练第一个caffemodel
一.前言 本文会详细地阐述caffe-windows的配置教程.由于博主自己也只是个在校学生,目前也写不了太深入的东西,所以准备从最基础的开始一步步来.个人的计划是分成配置和运行官方教程,利用自己的数 ...
- Android 自定义RadioButton实现
由于使用小米系统MIUI运行是RadioButton样式跟google Android API自定义的不一样,则我们可以定义任何想要的东东.没有做不到,只有想不到 Android 自定义RadioBu ...
- Django 数据库查询优化
Django数据层提供各种途径优化数据的访问,一个项目大量优化工作一般是放在后期来做,早期的优化是“万恶之源”,这是前人总结的经验,不无道理.如果事先理解Django的优化技巧,开发过程中稍稍留意,后 ...
- 【POJ 1984】Navigation Nightmare(带权并查集)
Navigation Nightmare Description Farmer John's pastoral neighborhood has N farms (2 <= N <= 40 ...
- 运行 maven install的时候出现错误 not a jre
原文转自jingyan.baidu.com/article/c85b7a6464d8be003bac95fb.html (linux下我直接执行第二步,错误解决) 在使用eclipse 运行 mave ...
- RMA Sales Order – Stuck with “Awaiting Return Disposition”
RMA Sales Order – Stuck with "Awaiting Return Disposition" Action : (P ...
- \u202e
document.write('\u202e1\u202e2\u202e3')
- STM32F0308开发环境的选择--CooCox CoIDE篇
STM32的开发环境有很多总,官方手册也提供了IAR Embedded Workbench.MDK-ARM和TrueSTUDIO这3种.今天我试用了CooCox CoIDE,是免费的集成开发环境,同T ...