FFmpeg从入门到牛掰(二):转封装(remux)讲解

FFmpeg从入门到牛掰(二):转封装(remux)讲解转载请注明出处 https blog csdn net impingo 项目地址 https github com im pingo pingos 转封装讲解转封装流程函数调用流程函数接口代码

大家好,欢迎来到IT知识分享网。

转载请注明出处:FFmpeg从入门到牛掰(二):转封装(remux)讲解
项目地址:https://github.com/im-pingo/pingos


承接上一篇文章,这里进行封装过程的讲解,如果对解复用(解封装)过程不了解的人请先阅读上篇文章(FFmpeg从入门到牛掰(一):解复用(demux)讲解) ,此篇文章将结合上篇内容完成转封装的操作

转封装流程

解复用

传递

输出

源媒体流或文件

解复用器

复用器

目标媒体流或文件

函数调用流程

Created with Raphaël 2.2.0 开始 avformat_alloc_output_context2 avformat_new_stream avcodec_parameters_copy 已经创建所有流 avio_open avformat_write_header av_interleaved_write_frame 没有输入数据 av_write_trailer avio_closep avformat_free_context 结束 yes no yes no

函数接口

int avformat_alloc_output_context2(AVFormatContext **ctx, ff_const59 AVOutputFormat *oformat, const char *format_name, const char *filename); 

创建AVFormatContext用于输出格式的format,对应的使用avformat_free_context()函数释放AVFormatContext。
ctx:该函数用于创建的AVFormatContext
oformat:指定创建的格式,如果此值为NULL,则以format_name或filename为准
format_name:用于指定输出的格式如“mp4”
filename:用于指定输出目录或url

AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c) 

在AVFormatContext输出的时候,如果想要输出音频和视频都需要通过该函数创建一条流操作句柄,每条流都需要填充codec参数,可以使用avcodec_parameters_copy从其他流的codec信息中填充codec参数。

int avio_open(AVIOContext **s, const char *url, int flags); 

打开输出文件或url

int avformat_write_header(AVFormatContext *s, AVDictionary **options); 

创建流的私有数据并且向输出文件写入流header

int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt); 

pkt中是存储的是媒体数据,通过该函数写入目标文件中

int av_write_trailer(AVFormatContext *s); 

向输出文件写入尾部信息,例如mp4文件中的moov box

需要注意

代码示例

#ifdef __cplusplus extern "C" { 
    #endif #include <libavutil/timestamp.h> #include <libavformat/avformat.h> #ifdef __cplusplus } #endif static void log_packet(const AVFormatContext *fmt_ctx, const AVPacket *pkt, const char *tag) { 
    AVRational *time_base = &fmt_ctx->streams[pkt->stream_index]->time_base; printf("%s: pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n", tag, av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, time_base), av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, time_base), av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, time_base), pkt->stream_index); } int main(int argc, char **argv) { 
    AVOutputFormat *ofmt = NULL; AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL; AVPacket pkt; const char *in_filename, *out_filename; int ret, i; int stream_index = 0; int *stream_mapping = NULL; int stream_mapping_size = 0; if (argc < 3) { 
    printf("usage: %s input output\n" "API example program to remux a media file with libavformat and libavcodec.\n" "The output format is guessed according to the file extension.\n" "\n", argv[0]); return 1; } in_filename = argv[1]; out_filename = argv[2]; if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) { 
    fprintf(stderr, "Could not open input file '%s'", in_filename); goto end; } if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) { 
    fprintf(stderr, "Failed to retrieve input stream information"); goto end; } av_dump_format(ifmt_ctx, 0, in_filename, 0); avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename); if (!ofmt_ctx) { 
    fprintf(stderr, "Could not create output context\n"); ret = AVERROR_UNKNOWN; goto end; } stream_mapping_size = ifmt_ctx->nb_streams; stream_mapping = av_mallocz_array(stream_mapping_size, sizeof(*stream_mapping)); if (!stream_mapping) { 
    ret = AVERROR(ENOMEM); goto end; } ofmt = ofmt_ctx->oformat; for (i = 0; i < ifmt_ctx->nb_streams; i++) { 
    AVStream *out_stream; AVStream *in_stream = ifmt_ctx->streams[i]; AVCodecParameters *in_codecpar = in_stream->codecpar; if (in_codecpar->codec_type != AVMEDIA_TYPE_AUDIO && in_codecpar->codec_type != AVMEDIA_TYPE_VIDEO && in_codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) { 
    stream_mapping[i] = -1; continue; } stream_mapping[i] = stream_index++; out_stream = avformat_new_stream(ofmt_ctx, NULL); if (!out_stream) { 
    fprintf(stderr, "Failed allocating output stream\n"); ret = AVERROR_UNKNOWN; goto end; } ret = avcodec_parameters_copy(out_stream->codecpar, in_codecpar); if (ret < 0) { 
    fprintf(stderr, "Failed to copy codec parameters\n"); goto end; } out_stream->codecpar->codec_tag = 0; } av_dump_format(ofmt_ctx, 0, out_filename, 1); if (!(ofmt->flags & AVFMT_NOFILE)) { 
    ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE); if (ret < 0) { 
    fprintf(stderr, "Could not open output file '%s'", out_filename); goto end; } } ret = avformat_write_header(ofmt_ctx, NULL); if (ret < 0) { 
    fprintf(stderr, "Error occurred when opening output file\n"); goto end; } while (1) { 
    AVStream *in_stream, *out_stream; ret = av_read_frame(ifmt_ctx, &pkt); if (ret < 0) break; in_stream = ifmt_ctx->streams[pkt.stream_index]; if (pkt.stream_index >= stream_mapping_size || stream_mapping[pkt.stream_index] < 0) { 
    av_packet_unref(&pkt); continue; } pkt.stream_index = stream_mapping[pkt.stream_index]; out_stream = ofmt_ctx->streams[pkt.stream_index]; log_packet(ifmt_ctx, &pkt, "in"); /* copy packet */ pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX); pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, 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; log_packet(ofmt_ctx, &pkt, "out"); ret = av_interleaved_write_frame(ofmt_ctx, &pkt); if (ret < 0) { 
    fprintf(stderr, "Error muxing packet\n"); break; } av_packet_unref(&pkt); } av_write_trailer(ofmt_ctx); end: avformat_close_input(&ifmt_ctx); /* close output */ if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE)) avio_closep(&ofmt_ctx->pb); avformat_free_context(ofmt_ctx); av_freep(&stream_mapping); if (ret < 0 && ret != AVERROR_EOF) { 
    fprintf(stderr, "Error occurred: %s\n", av_err2str(ret)); return 1; } return 0; } 

交流群:

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/152786.html

(0)
上一篇 2025-03-07 15:33
下一篇 2025-03-07 15:45

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注