最简单的基于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 ...
随机推荐
- 【资料目录收藏】.NET开发必看资料53个 经典源码77个
简单描述:为大家整理了下载中心.net资料,都是比较热的,好评率比较高的,做了一个可收藏的下载目录,希望大家喜欢~ 基于.net构架的留言板项目大全源码 http://down.51cto.com/z ...
- SQL(笔试题)网站上的广告位是轮播的,每天某一广告位最多可轮播的广告数量是有限制的,比如A广告位,每天只能轮播三个广告,但销售人员在销售广告位时并不考虑此限制,要求查询出合同表中,超过广告位轮播数量的合同。
合同表 Orders OrderID Positioncode Startdate Enddate 1 A 2006-11-01 2006-11-03 2 C 2006-11-02 2006-11-0 ...
- 加JENKINS的SLAVE节点(LINUX)要注意的事项
从昨天下午到现在,终于解决了所有的问题.作如下记录要点: 1,从节点只要建好目录,JENKINS的包,MASTER会推送过来. 2,ANT,MAVEN之类的,要配置好环境变量,PROFILE.D .B ...
- IE连EXCHANGE的HTTPS时,出现错误
"There is a problem with this website's security certificate" 这种问题,一般是SSL或CA认证证书的问题. 一般从服务 ...
- [译]GotW #1: Variable Initialization
原文地址:http://herbsutter.com/2013/05/09/gotw-1-solution/ 第一个问题强调的是要明白自己在写什么的重要性.下面有几行简单的代码--它们大多数之间都有区 ...
- CF 370
A:http://codeforces.com/problemset/problem/370/A #include<stdio.h> #include<string.h> #i ...
- BZOJ_1208_&_Codevs_1258_[HNOI2004]_宠物收养所_(平衡树/set)
描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1208 (据说codevs要更新?就不放codevs的地址了吧...) 有宠物和人,每个单位都有 ...
- 转自 x_x的百度空间
空华人生 by 淡漠的心情 昨天,又昨天. 今天,又今天. 明天,又明天. 日历渐渐稀薄,忽然发现,那是时间的痕迹. 似乎,总是在麻木的等待. 何时,才能历尽. 再算算,我又还有多少天 ...
- input框自动填充内容背景颜色为黄色解决方法
谷歌浏览器input自动填充内容,背景色会是黄色,想改的话: input:-webkit-autofill { box-shadow: 0 0 0px 1000px white inset;} 这种方 ...
- SignalR--Http/WebSockets消息推送
官网API: http://www.asp.net/signalr/overview/signalr-20/hubs-api/hubs-api-guide-server 参考: http://www. ...