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.
This commit is contained in:
Anton Khirnov 2024-09-10 11:22:40 +02:00
parent 78170120ca
commit 70f7bbeade
3 changed files with 45 additions and 21 deletions

View File

@ -858,7 +858,7 @@ int dec_request_view(Decoder *dec, const ViewSpecifier *vs,
SchedulerNode *src); SchedulerNode *src);
int enc_alloc(Encoder **penc, const AVCodec *codec, 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); void enc_free(Encoder **penc);
int enc_open(void *opaque, const AVFrame *frame); int enc_open(void *opaque, const AVFrame *frame);

View File

@ -39,6 +39,10 @@
#include "libavcodec/avcodec.h" #include "libavcodec/avcodec.h"
struct Encoder { struct Encoder {
const AVClass *class;
void *log_parent;
char log_name[32];
// combined size of all the packets received from the encoder // combined size of all the packets received from the encoder
uint64_t data_size; uint64_t data_size;
@ -68,8 +72,22 @@ void enc_free(Encoder **penc)
av_freep(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, int enc_alloc(Encoder **penc, const AVCodec *codec,
Scheduler *sch, unsigned sch_idx) Scheduler *sch, unsigned sch_idx, void *log_parent)
{ {
Encoder *enc; Encoder *enc;
@ -79,9 +97,14 @@ int enc_alloc(Encoder **penc, const AVCodec *codec,
if (!enc) if (!enc)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
enc->class = &enc_class;
enc->log_parent = log_parent;
enc->sch = sch; enc->sch = sch;
enc->sch_idx = sch_idx; enc->sch_idx = sch_idx;
snprintf(enc->log_name, sizeof(enc->log_name), "enc:%s", codec->name);
*penc = enc; *penc = enc;
return 0; 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); ret = hw_device_setup_for_encode(ost, frame ? frame->hw_frames_ctx : NULL);
if (ret < 0) { 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)); "Encoding hardware device setup failed: %s\n", av_err2str(ret));
return ret; return ret;
} }
if ((ret = avcodec_open2(ost->enc_ctx, enc, NULL)) < 0) { if ((ret = avcodec_open2(ost->enc_ctx, enc, NULL)) < 0) {
if (ret != AVERROR_EXPERIMENTAL) 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"); "incorrect parameters such as bit_rate, rate, width or height.\n");
return ret; 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 && 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 */) 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"); " It takes bits/s as argument, not kbits/s\n");
ret = avcodec_parameters_from_context(ost->par_in, ost->enc_ctx); ret = avcodec_parameters_from_context(ost->par_in, ost->enc_ctx);
if (ret < 0) { if (ret < 0) {
av_log(ost, AV_LOG_FATAL, av_log(e, AV_LOG_FATAL,
"Error initializing the output stream codec context.\n"); "Error initializing the output stream codec context.\n");
return ret; return ret;
} }
@ -375,7 +398,7 @@ static int do_subtitle_out(OutputFile *of, OutputStream *ost, const AVSubtitle *
int64_t pts; int64_t pts;
if (sub->pts == AV_NOPTS_VALUE) { 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; return exit_on_error ? AVERROR(EINVAL) : 0;
} }
if ((of->start_time != AV_NOPTS_VALUE && sub->pts < of->start_time)) 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); subtitle_out_size = avcodec_encode_subtitle(enc, pkt->data, pkt->size, &local_sub);
if (subtitle_out_size < 0) { 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; return subtitle_out_size;
} }
@ -619,7 +642,7 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame,
ost->samples_encoded += frame->nb_samples; ost->samples_encoded += frame->nb_samples;
if (debug_ts) { 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", "frame_pts:%s frame_pts_time:%s time_base:%d/%d\n",
type_desc, type_desc,
av_ts2str(frame->pts), av_ts2timestr(frame->pts, &enc->time_base), 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); ret = avcodec_send_frame(enc, frame);
if (ret < 0 && !(ret == AVERROR_EOF && !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); type_desc);
return ret; return ret;
} }
@ -659,7 +682,7 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame,
return 0; return 0;
} else if (ret < 0) { } else if (ret < 0) {
if (ret != AVERROR_EOF) 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; return ret;
} }
@ -693,7 +716,7 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame,
e->packets_encoded); e->packets_encoded);
if (debug_ts) { 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 " "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s "
"duration:%s duration_time:%s\n", "duration:%s duration_time:%s\n",
type_desc, type_desc,
@ -764,6 +787,7 @@ force_keyframe:
static int frame_encode(OutputStream *ost, AVFrame *frame, AVPacket *pkt) static int frame_encode(OutputStream *ost, AVFrame *frame, AVPacket *pkt)
{ {
Encoder *e = ost->enc;
OutputFile *of = ost->file; OutputFile *of = ost->file;
enum AVMediaType type = ost->type; enum AVMediaType type = ost->type;
@ -782,7 +806,7 @@ static int frame_encode(OutputStream *ost, AVFrame *frame, AVPacket *pkt)
if (type == AVMEDIA_TYPE_VIDEO) { if (type == AVMEDIA_TYPE_VIDEO) {
frame->quality = ost->enc_ctx->global_quality; 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 FFMPEG_OPT_TOP
if (ost->top_field_first >= 0) { if (ost->top_field_first >= 0) {
@ -793,7 +817,7 @@ static int frame_encode(OutputStream *ost, AVFrame *frame, AVPacket *pkt)
} else { } else {
if (!(ost->enc_ctx->codec->capabilities & AV_CODEC_CAP_PARAM_CHANGE) && if (!(ost->enc_ctx->codec->capabilities & AV_CODEC_CAP_PARAM_CHANGE) &&
ost->enc_ctx->ch_layout.nb_channels != frame->ch_layout.nb_channels) { 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"); "Audio channel count changed and encoder does not support parameter changes\n");
return 0; return 0;
} }
@ -867,14 +891,14 @@ int encoder_thread(void *arg)
input_status = sch_enc_receive(e->sch, e->sch_idx, et.frame); input_status = sch_enc_receive(e->sch, e->sch_idx, et.frame);
if (input_status < 0) { if (input_status < 0) {
if (input_status == AVERROR_EOF) { 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) if (e->opened)
break; 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); ret = AVERROR(EINVAL);
} else { } 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)); av_err2str(ret));
ret = input_status; ret = input_status;
} }
@ -893,9 +917,9 @@ int encoder_thread(void *arg)
if (ret < 0) { if (ret < 0) {
if (ret == AVERROR_EOF) 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 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)); av_err2str(ret));
break; break;
} }
@ -905,7 +929,7 @@ int encoder_thread(void *arg)
if (ret == 0 || ret == AVERROR_EOF) { if (ret == 0 || ret == AVERROR_EOF) {
ret = frame_encode(ost, NULL, et.pkt); ret = frame_encode(ost, NULL, et.pkt);
if (ret < 0 && ret != AVERROR_EOF) 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)); av_err2str(ret));
} }

View File

@ -1227,7 +1227,7 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
return ret; return ret;
ms->sch_idx_enc = 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) if (ret < 0)
return ret; return ret;