图示

图片引用自
封装步骤
- avformat_open_input 打开输入文件,初始化AVFormatContext结构体
- avformat_find_stream_info 查找流信息
- avformat_alloc_output_context2 申请输出容器上下文
- avcodec_parameters_to_context / avcodec_parameters_from_context 拷贝输入容器中流的参数到输出容器中
- avio_open 打开输出IO上下文
- avformat_write_header 写输出的文件头
- av_read_frame / av_interleaved_write_frame 从输入读取帧,优化时间戳,写入到输出
- 结束,释放
代码
#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)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。