From 70f7bbeade57ab5c7fa14b2450d46fb3b87466d7 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Tue, 10 Sep 2024 11:22:40 +0200 Subject: [PATCH] fftools/ffmpeg_enc: add an AVClass to Encoder Log decoder messages to the encoder rather than OutputStream. This is a step towards decoupling encoders from muxers, similarly to what was previously done to decoders and demuxers. --- fftools/ffmpeg.h | 2 +- fftools/ffmpeg_enc.c | 62 +++++++++++++++++++++++++++------------ fftools/ffmpeg_mux_init.c | 2 +- 3 files changed, 45 insertions(+), 21 deletions(-) diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index 733d551fa4..122372440f 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -858,7 +858,7 @@ int dec_request_view(Decoder *dec, const ViewSpecifier *vs, SchedulerNode *src); int enc_alloc(Encoder **penc, const AVCodec *codec, - Scheduler *sch, unsigned sch_idx); + Scheduler *sch, unsigned sch_idx, void *log_parent); void enc_free(Encoder **penc); int enc_open(void *opaque, const AVFrame *frame); diff --git a/fftools/ffmpeg_enc.c b/fftools/ffmpeg_enc.c index c1c8aa0e78..2e1c7f27c1 100644 --- a/fftools/ffmpeg_enc.c +++ b/fftools/ffmpeg_enc.c @@ -39,6 +39,10 @@ #include "libavcodec/avcodec.h" struct Encoder { + const AVClass *class; + void *log_parent; + char log_name[32]; + // combined size of all the packets received from the encoder uint64_t data_size; @@ -68,8 +72,22 @@ void enc_free(Encoder **penc) av_freep(penc); } +static const char *enc_item_name(void *obj) +{ + const Encoder *e = obj; + + return e->log_name; +} + +static const AVClass enc_class = { + .class_name = "Encoder", + .version = LIBAVUTIL_VERSION_INT, + .parent_log_context_offset = offsetof(Encoder, log_parent), + .item_name = enc_item_name, +}; + int enc_alloc(Encoder **penc, const AVCodec *codec, - Scheduler *sch, unsigned sch_idx) + Scheduler *sch, unsigned sch_idx, void *log_parent) { Encoder *enc; @@ -79,9 +97,14 @@ int enc_alloc(Encoder **penc, const AVCodec *codec, if (!enc) return AVERROR(ENOMEM); + enc->class = &enc_class; + enc->log_parent = log_parent; + enc->sch = sch; enc->sch_idx = sch_idx; + snprintf(enc->log_name, sizeof(enc->log_name), "enc:%s", codec->name); + *penc = enc; return 0; @@ -314,14 +337,14 @@ int enc_open(void *opaque, const AVFrame *frame) ret = hw_device_setup_for_encode(ost, frame ? frame->hw_frames_ctx : NULL); if (ret < 0) { - av_log(ost, AV_LOG_ERROR, + av_log(e, AV_LOG_ERROR, "Encoding hardware device setup failed: %s\n", av_err2str(ret)); return ret; } if ((ret = avcodec_open2(ost->enc_ctx, enc, NULL)) < 0) { if (ret != AVERROR_EXPERIMENTAL) - av_log(ost, AV_LOG_ERROR, "Error while opening encoder - maybe " + av_log(e, AV_LOG_ERROR, "Error while opening encoder - maybe " "incorrect parameters such as bit_rate, rate, width or height.\n"); return ret; } @@ -333,12 +356,12 @@ int enc_open(void *opaque, const AVFrame *frame) if (ost->enc_ctx->bit_rate && ost->enc_ctx->bit_rate < 1000 && ost->enc_ctx->codec_id != AV_CODEC_ID_CODEC2 /* don't complain about 700 bit/s modes */) - av_log(ost, AV_LOG_WARNING, "The bitrate parameter is set too low." + av_log(e, AV_LOG_WARNING, "The bitrate parameter is set too low." " It takes bits/s as argument, not kbits/s\n"); ret = avcodec_parameters_from_context(ost->par_in, ost->enc_ctx); if (ret < 0) { - av_log(ost, AV_LOG_FATAL, + av_log(e, AV_LOG_FATAL, "Error initializing the output stream codec context.\n"); return ret; } @@ -375,7 +398,7 @@ static int do_subtitle_out(OutputFile *of, OutputStream *ost, const AVSubtitle * int64_t pts; if (sub->pts == AV_NOPTS_VALUE) { - av_log(ost, AV_LOG_ERROR, "Subtitle packets must have a pts\n"); + av_log(e, AV_LOG_ERROR, "Subtitle packets must have a pts\n"); return exit_on_error ? AVERROR(EINVAL) : 0; } if ((of->start_time != AV_NOPTS_VALUE && sub->pts < of->start_time)) @@ -424,7 +447,7 @@ static int do_subtitle_out(OutputFile *of, OutputStream *ost, const AVSubtitle * subtitle_out_size = avcodec_encode_subtitle(enc, pkt->data, pkt->size, &local_sub); if (subtitle_out_size < 0) { - av_log(ost, AV_LOG_FATAL, "Subtitle encoding failed\n"); + av_log(e, AV_LOG_FATAL, "Subtitle encoding failed\n"); return subtitle_out_size; } @@ -619,7 +642,7 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame, ost->samples_encoded += frame->nb_samples; if (debug_ts) { - av_log(ost, AV_LOG_INFO, "encoder <- type:%s " + av_log(e, AV_LOG_INFO, "encoder <- type:%s " "frame_pts:%s frame_pts_time:%s time_base:%d/%d\n", type_desc, av_ts2str(frame->pts), av_ts2timestr(frame->pts, &enc->time_base), @@ -634,7 +657,7 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame, ret = avcodec_send_frame(enc, frame); if (ret < 0 && !(ret == AVERROR_EOF && !frame)) { - av_log(ost, AV_LOG_ERROR, "Error submitting %s frame to the encoder\n", + av_log(e, AV_LOG_ERROR, "Error submitting %s frame to the encoder\n", type_desc); return ret; } @@ -659,7 +682,7 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame, return 0; } else if (ret < 0) { if (ret != AVERROR_EOF) - av_log(ost, AV_LOG_ERROR, "%s encoding failed\n", type_desc); + av_log(e, AV_LOG_ERROR, "%s encoding failed\n", type_desc); return ret; } @@ -693,7 +716,7 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame, e->packets_encoded); if (debug_ts) { - av_log(ost, AV_LOG_INFO, "encoder -> type:%s " + av_log(e, AV_LOG_INFO, "encoder -> type:%s " "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s " "duration:%s duration_time:%s\n", type_desc, @@ -764,6 +787,7 @@ force_keyframe: static int frame_encode(OutputStream *ost, AVFrame *frame, AVPacket *pkt) { + Encoder *e = ost->enc; OutputFile *of = ost->file; enum AVMediaType type = ost->type; @@ -782,7 +806,7 @@ static int frame_encode(OutputStream *ost, AVFrame *frame, AVPacket *pkt) if (type == AVMEDIA_TYPE_VIDEO) { frame->quality = ost->enc_ctx->global_quality; - frame->pict_type = forced_kf_apply(ost, &ost->kf, frame); + frame->pict_type = forced_kf_apply(e, &ost->kf, frame); #if FFMPEG_OPT_TOP if (ost->top_field_first >= 0) { @@ -793,7 +817,7 @@ static int frame_encode(OutputStream *ost, AVFrame *frame, AVPacket *pkt) } else { if (!(ost->enc_ctx->codec->capabilities & AV_CODEC_CAP_PARAM_CHANGE) && ost->enc_ctx->ch_layout.nb_channels != frame->ch_layout.nb_channels) { - av_log(ost, AV_LOG_ERROR, + av_log(e, AV_LOG_ERROR, "Audio channel count changed and encoder does not support parameter changes\n"); return 0; } @@ -867,14 +891,14 @@ int encoder_thread(void *arg) input_status = sch_enc_receive(e->sch, e->sch_idx, et.frame); if (input_status < 0) { if (input_status == AVERROR_EOF) { - av_log(ost, AV_LOG_VERBOSE, "Encoder thread received EOF\n"); + av_log(e, AV_LOG_VERBOSE, "Encoder thread received EOF\n"); if (e->opened) break; - av_log(ost, AV_LOG_ERROR, "Could not open encoder before EOF\n"); + av_log(e, AV_LOG_ERROR, "Could not open encoder before EOF\n"); ret = AVERROR(EINVAL); } else { - av_log(ost, AV_LOG_ERROR, "Error receiving a frame for encoding: %s\n", + av_log(e, AV_LOG_ERROR, "Error receiving a frame for encoding: %s\n", av_err2str(ret)); ret = input_status; } @@ -893,9 +917,9 @@ int encoder_thread(void *arg) if (ret < 0) { if (ret == AVERROR_EOF) - av_log(ost, AV_LOG_VERBOSE, "Encoder returned EOF, finishing\n"); + av_log(e, AV_LOG_VERBOSE, "Encoder returned EOF, finishing\n"); else - av_log(ost, AV_LOG_ERROR, "Error encoding a frame: %s\n", + av_log(e, AV_LOG_ERROR, "Error encoding a frame: %s\n", av_err2str(ret)); break; } @@ -905,7 +929,7 @@ int encoder_thread(void *arg) if (ret == 0 || ret == AVERROR_EOF) { ret = frame_encode(ost, NULL, et.pkt); if (ret < 0 && ret != AVERROR_EOF) - av_log(ost, AV_LOG_ERROR, "Error flushing encoder: %s\n", + av_log(e, AV_LOG_ERROR, "Error flushing encoder: %s\n", av_err2str(ret)); } diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c index 8afb018de8..1b75430e4e 100644 --- a/fftools/ffmpeg_mux_init.c +++ b/fftools/ffmpeg_mux_init.c @@ -1227,7 +1227,7 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, return ret; ms->sch_idx_enc = ret; - ret = enc_alloc(&ost->enc, enc, mux->sch, ms->sch_idx_enc); + ret = enc_alloc(&ost->enc, enc, mux->sch, ms->sch_idx_enc, ost); if (ret < 0) return ret;