ffmpeg转封装文件

图示

ffmpeg转封装文件

图片引用自

封装步骤

  1. avformat_open_input 打开输入文件,初始化AVFormatContext结构体
  2. avformat_find_stream_info 查找流信息
  3. avformat_alloc_output_context2 申请输出容器上下文
  4. avcodec_parameters_to_context / avcodec_parameters_from_context 拷贝输入容器中流的参数到输出容器中
  5. avio_open 打开输出IO上下文
  6. avformat_write_header 写输出的文件头
  7. av_read_frame / av_interleaved_write_frame 从输入读取帧,优化时间戳,写入到输出
  8. 结束,释放

代码

#include <stdio.h>
#include <error_code.h>

extern "C"{
#include <libavformat/avformat.h>
#include <libavutil/log.h>
};

int transcode(const char* input , const char* output){
    int ret = ERROR_SUCCESS;
    //av_register_all();

    // for aac
    AVBSFContext *avbsf_ctx = NULL;
    const AVBitStreamFilter* av_bsf = av_bsf_get_by_name("aac_adtstoasc");
    ret = av_bsf_alloc(av_bsf , &avbsf_ctx);
    if(ret != 0){
        av_log(NULL , AV_LOG_ERROR , "eno:[%d] error to alloc bsf\n");
        return ERROR_ALLOC_BSF;
    }
    //av_bsf_init(avbsf_ctx);

    AVFormatContext *ifmt_ctx = NULL;
    AVFormatContext *ofmt_ctx;
    AVOutputFormat  *ofmt = NULL;

    ret = avformat_open_input(&ifmt_ctx , input , NULL , NULL);
    if(ret != 0){
        av_log(NULL , AV_LOG_ERROR , "eno:[%d] error to open the input file\n" , ret);
        return ERROR_OPEN_INPUT;
    }

    ret = avformat_find_stream_info(ifmt_ctx , NULL);
    if(ret < 0){
        av_log(NULL , AV_LOG_ERROR , "eno:[%d] error to find the input file stream info\n" , ret);
        return ERROR_FIND_STREAM;
    }
    av_dump_format(ifmt_ctx , 0 , input , 0);

    ret = avformat_alloc_output_context2(&ofmt_ctx , NULL , NULL , output);
    if(ret < 0){
        av_log(NULL , AV_LOG_ERROR , "eno:[%d] error to alloc output format context\n" , ret);
        return ERROR_ALLOC_OUTPUT;
    }

    ofmt = ofmt_ctx->oformat;
    for(int i = 0 ; i < ifmt_ctx->nb_streams ; i++){
        AVStream *in_stream = ifmt_ctx->streams[i];
        AVCodec *codec = avcodec_find_decoder(in_stream->codecpar->codec_id);
        AVStream *out_stream = avformat_new_stream(ofmt_ctx , codec);
        if(!out_stream){
            av_log(NULL , AV_LOG_ERROR , "eno:[%d] error to alloc new stream [%d] for output fmtctx\n" , ret, i);
            return ERROR_ALLOC_STREAM;
        }

        AVCodecContext *p_codec_ctx = avcodec_alloc_context3(codec);
        ret = avcodec_parameters_to_context(p_codec_ctx , in_stream->codecpar);
        if(ret < 0){
            av_log(NULL , AV_LOG_ERROR , "eno:[%d] error to praramters to context stream [%d] parameters to outstream\n" , ret, i);
            return ERROR_COPY_PARAMS;
        }
        p_codec_ctx->codec_tag = 0;

        if(ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER){
            p_codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
        }

        ret = avcodec_parameters_from_context(out_stream->codecpar , p_codec_ctx);
        if(ret < 0){
            av_log(NULL , AV_LOG_ERROR , "eno:[%d] error to paramters codec paramter \n" , ret);
        }
    }

    av_dump_format(ofmt_ctx , NULL , output , 1);

    AVPacket pkt;
    av_init_packet(&pkt);
    pkt.data = NULL;
    pkt.size = 0;

    if (!(ofmt->flags & AVFMT_NOFILE)) {
        ret = avio_open(&ofmt_ctx->pb, output, AVIO_FLAG_WRITE);
        if (ret < 0) {
            av_log(NULL, AV_LOG_ERROR, "eno:[%d] error to open the output file to write\n", ret);
            return ERROR_AVIO_OPEN;
        }
    }

    ret = avformat_write_header(ofmt_ctx , NULL);
    if(ret < 0){
        av_log(NULL , AV_LOG_ERROR , "eno:[%d] error to write the header for output\n" , ret);
        return ERROR_WRITE_HEAD;
    }

    int index = 0;
    while(1){
        ret = av_read_frame(ifmt_ctx , &pkt);
        if(ret < 0){
            av_log(NULL , AV_LOG_WARNING , "read frame error\n");
            break;
        }

        AVStream* in_stream = ifmt_ctx->streams[pkt.stream_index];
        AVStream* out_stream = ofmt_ctx->streams[pkt.stream_index];
        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;

        //for aac
        if(pkt.stream_index == 1 ){
            ret = av_bsf_send_packet(avbsf_ctx , &pkt);
            if(ret != 0){
                av_log(NULL , AV_LOG_WARNING , "wno:[%d] filter audio error\n",ret);
                continue;
            }
            ret = av_bsf_receive_packet(avbsf_ctx , &pkt);
        }

        ret = av_interleaved_write_frame(ofmt_ctx , &pkt);
        if(ret < 0){
            index++;
            av_packet_unref(&pkt);
            continue;
        }
        av_log(NULL , AV_LOG_INFO , "write frame [%d] ok\n" , index);
        index++;
        av_packet_unref(&pkt);
    }

    av_write_trailer(ofmt_ctx);
    avformat_close_input(&ifmt_ctx);
    avio_close(ofmt_ctx->pb);
    avformat_free_context(ofmt_ctx);
    return ret;
}

int main(int argc , char** argv) {
    if(argc < 2){
        av_log(NULL, AV_LOG_INFO , "usage: ./ffplush input output\n");
        av_log(NULL, AV_LOG_INFO , "example: ./ffplush a.ts b.mp4\n");
        return -1;
    }

    int ret = transcode(argv[1] , argv[2]);
    return ret;
}

编译(CMake)

cmake_minimum_required(VERSION 3.10)
project(ffplush)

set(CMAKE_CXX_STANDARD 98)

include_directories(./src /opt/libs/include)
link_directories(/opt/libs/lib/)

set(SOURCE_FILES ./src/main.cpp)
aux_source_directory(./src SOURCE_FILES)

add_executable(ffplush ${SOURCE_FILES})

target_link_libraries(ffplush -lavformat)
target_link_libraries(ffplush -lavcodec)
target_link_libraries(ffplush -lavutil)
target_link_libraries(ffplush -lswresample)
target_link_libraries(ffplush -lpthread)
target_link_libraries(ffplush -lz)
target_link_libraries(ffplush -lm)
target_link_libraries(ffplush -lbz2)
target_link_libraries(ffplush -lrt)

相关推荐