FFmpeg将mp4格式视频转为flv

时间:2025-03-08 21:44:58
#include <libavutil/> #include <libavformat/> #include "" 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 converterVideo(const char *in_filename, const char *out_filename) { AVOutputFormat *outfmt = NULL; //输出格式 AVFormatContext *infmt_ctx = NULL, *outfmt_ctx = NULL;//输入、输出上下文 AVPacket pkt; int ret , i; int stream_index = 0; int *stream_mapping = NULL;//数组用于存放输出文件流的Index int stream_mapping_size = 0;//输入文件中流的总数量 av_register_all(); //打开输入文件为infmt_ctx分配内存 ret = avformat_open_input(&infmt_ctx, in_filename, 0, 0); if (ret < 0) { fprintf(stderr, "Could not open input file '%s'", in_filename); goto end; } //检索输入文件的流信息 ret = avformat_find_stream_info(infmt_ctx, NULL); if (ret < 0) { fprintf(stderr, "Failed to retrieve input stream information"); goto end; } //打印输入文件相关信息 av_dump_format(infmt_ctx, 0, in_filename, 0); //为输出上下文环境分配内存 avformat_alloc_output_context2(&outfmt_ctx, NULL, NULL, out_filename); if (!outfmt_ctx) { fprintf(stderr, "Could not create output context\n"); ret = AVERROR_UNKNOWN; goto end; } //输入文件流的数量 stream_mapping_size = infmt_ctx->nb_streams; //分配stream_mapping_size段内存,每段内存大小是sizeof(*stream_mapping)->如果有音频和视频,那就是,2段为整型的内存 stream_mapping = av_mallocz_array(stream_mapping_size, sizeof(*stream_mapping)); if (!stream_mapping) { ret = AVERROR(ENOMEM); goto end; } //输出文件格式 outfmt = outfmt_ctx->oformat; //遍历输入文件中的每一路流,对于每一路流都要创建一个新的流进行输出 for (i = 0; i < infmt_ctx->nb_streams; i++) { AVStream *out_stream = NULL;//输出流 AVStream *in_stream = infmt_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; } //对于输出流的index重新编号 stream_mapping[i] = stream_index++; //创建一个对应的输出流 out_stream = avformat_new_stream(outfmt_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(outfmt_ctx, 0, out_filename, 1); if (!(outfmt->flags & AVFMT_NOFILE)) { ret = avio_open(&outfmt_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(outfmt_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(infmt_ctx, &pkt); if (ret < 0) { //读取完后退出循环 break; } in_stream = infmt_ctx->streams[pkt.stream_index]; //如果当前包的流不是音频、视频、就不用做接下来的处理 if (pkt.stream_index >= stream_mapping_size || stream_mapping[pkt.stream_index] < 0) { av_packet_unref(&pkt); continue; } //按照输出流的index给pkt重新编号 pkt.stream_index = stream_mapping[pkt.stream_index]; //根据pkt的stream_index获取对应的输出流 out_stream = outfmt_ctx->streams[pkt.stream_index]; //对pts、dts、duration 进行时间基转换,不同格式时间基都不一样,不转换会导致音视频同步问题 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(outfmt_ctx, &pkt, "out"); //将处理好的pkt写入输出文件 ret = av_interleaved_write_frame(outfmt_ctx, &pkt); if (ret < 0) { fprintf(stderr, "Error muxing packer\n"); break; } av_packet_unref(&pkt); } // 写入新的多媒体文件尾 av_write_trailer(outfmt_ctx); end: avformat_close_input(&infmt_ctx); if(outfmt_ctx && !(outfmt->flags & AVFMT_NOFILE)) { avio_closep(&outfmt_ctx->pb); } avformat_free_context(outfmt_ctx); av_freep(&stream_mapping); if (ret < 0 && ret != AVERROR_EOF) { fprintf(stderr, "Error occurred: %s\n", av_err2str(ret)); return 1; } return 0; }