本文介绍一个基于FFMPEG的封装格式转换器。所谓的封装格式转换,就是在AVI,FLV,MKV,MP4这些格式之间转换(相应.avi,.flv,.mkv,.mp4文件)。须要注意的是,本程序并不进行视音频的编码和解码工作。而是直接将视音频压缩码流从一种封装格式文件里获取出来然后打包成第二种封装格式的文件。传统的转码程序工作原理例如以下图所看到的:

上图例举了一个举例: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下载地址:

http://download.csdn.net/detail/leixiaohua1020/7323491

最简单的基于FFMPEG的封装格式转换器(无编解码)的更多相关文章

  1. 最简单的基于FFmpeg的封装格式处理:视音频分离器简化版(demuxer-simple)

    ===================================================== 最简单的基于FFmpeg的封装格式处理系列文章列表: 最简单的基于FFmpeg的封装格式处理 ...

  2. 最简单的基于FFmpeg的封装格式处理:视音频复用器(muxer)

    ===================================================== 最简单的基于FFmpeg的封装格式处理系列文章列表: 最简单的基于FFmpeg的封装格式处理 ...

  3. 最简单的基于FFmpeg的封装格式处理:视音频分离器(demuxer)

    ===================================================== 最简单的基于FFmpeg的封装格式处理系列文章列表: 最简单的基于FFmpeg的封装格式处理 ...

  4. 最简单的基于FFmpeg的推流器(以推送RTMP为例)

    ===================================================== 最简单的基于FFmpeg的推流器系列文章列表: <最简单的基于FFmpeg的推流器(以 ...

  5. 最简单的基于FFMPEG的转码程序

    本文介绍一个简单的基于FFmpeg的转码器.它可以将一种视频格式(包括封转格式和编码格式)转换为另一种视频格式.转码器在视音频编解码处理的程序中,属于一个比较复杂的东西.因为它结合了视频的解码和编码. ...

  6. 最简单的基于FFMPEG的音频编码器(PCM编码为AAC)

    http://blog.csdn.net/leixiaohua1020/article/details/25430449 本文介绍一个最简单的基于FFMPEG的音频编码器.该编码器实现了PCM音频采样 ...

  7. 最简单的基于FFMPEG的视频编码器(YUV编码为H.264)

    本文介绍一个最简单的基于FFMPEG的视频编码器.该编码器实现了YUV420P的像素数据编码为H.264的压缩编码数据.编码器代码十分简单,可是每一行代码都非常重要,适合好好研究一下.弄清楚了本代码也 ...

  8. 最简单的基于FFMPEG+SDL的视频播放器 ver2 (採用SDL2.0)

    ===================================================== 最简单的基于FFmpeg的视频播放器系列文章列表: 100行代码实现最简单的基于FFMPEG ...

  9. 最简单的基于FFmpeg的解码器-纯净版(不包含libavformat)

    ===================================================== 最简单的基于FFmpeg的视频播放器系列文章列表: 100行代码实现最简单的基于FFMPEG ...

随机推荐

  1. 【ASP.NET】从服务器端注册客户端脚本

    一.在Asp.net 服务端处理脚本,一般都用 ClientScriptManager ,即web窗体服务端的this.ClientScript.该对象比较常用的方法: 1.RegisterArray ...

  2. 开发C# .net时使用的数据库操作类SqlHelp.cs

    练习开发WPF程序的时候,是这样写的,虽然很简单,相必很多新手会用到,所以拿来共享一下, using System; using System.Collections.Generic; using S ...

  3. linux JAVA JDK环境配置

    export JAVA_HOME=/usr/local/jdk1.7.0_45export JRE_HOME=/usr/local/jdk1.7.0_45/jreexport CLASSPATH=.: ...

  4. csu 10月 月赛 I 题 The Contest

    Description 殷犇有很多队员.他们都认为自己是最强的,于是,一场比赛开始了~ 于是安叔主办了一场比赛,比赛有n个题目,每个题目都有一个价值Pi和相对能力消耗Wi,但是有些题目因为太坑不能同时 ...

  5. Dynamips/Dynagen模拟CISCO路由环境

    今天将<网络互连技术>--路由,交换与远程访问实训教程的实验书拿出来了看了部门. 搭建了一个基于DYNAGEN的虚拟环境. 归纳一下大约步骤: ~~~~~~~~~~~~~~ 一,在WIND ...

  6. android View 关于transient

    今天来研究一下 ListView 的删除动画 由于 ListView 卷动时会把画面上的 item 重用以显示不同数据 这样会导致我们可能会删除到非正确的 item 或是出现显示上的问题(该 item ...

  7. 使用android.view.TouchDelegate扩大View的触摸点击区域

    Android4.0设计规定的有效可触摸的UI元素标准是48dp,转化为一个物理尺寸约为9毫米.7~10毫米,这是一个用户手指能准确并且舒适触摸的区域. 如下图所示,你的UI元素可能小于48dp,图标 ...

  8. git tag的使用

    查看所有的标签git tag 删除某一个标签git tag -d tagName 创建带注释的标签 git tag -a tagName -m "annotate" 轻量级标签 g ...

  9. perl静态编译DBD

    编译DBD 项目中经常使用perl,但perl在连接数据库时,需要依赖DBI,DBD驱动,但默认安装DBD驱动时,需要依赖数据库的lib库. 比如perl连接MySQL,需要安装MySQL clien ...

  10. java基于xml配置的通用excel单表数据导入组件(二、xml配置文件解析加载)

    1.BN_ImportExcel.java 对应xml主节点属性 package XXXXX.manage.importexcel; import java.io.Serializable; impo ...