mirror of https://git.ffmpeg.org/ffmpeg.git
fftools/ffmpeg_enc: split Encoder into a private and public part
Similar to what was previously done for other components, e.g. decoders
(see 3b84140a1b
).
Start by moving {samples,frames}_encoded into the public struct.
This commit is contained in:
parent
f295b4d8a0
commit
434377a764
|
@ -569,7 +569,13 @@ typedef struct KeyframeForceCtx {
|
||||||
int dropped_keyframe;
|
int dropped_keyframe;
|
||||||
} KeyframeForceCtx;
|
} KeyframeForceCtx;
|
||||||
|
|
||||||
typedef struct Encoder Encoder;
|
typedef struct Encoder {
|
||||||
|
const AVClass *class;
|
||||||
|
|
||||||
|
// number of frames/samples sent to the encoder
|
||||||
|
uint64_t frames_encoded;
|
||||||
|
uint64_t samples_encoded;
|
||||||
|
} Encoder;
|
||||||
|
|
||||||
enum CroppingType {
|
enum CroppingType {
|
||||||
CROP_DISABLED = 0,
|
CROP_DISABLED = 0,
|
||||||
|
@ -621,9 +627,6 @@ typedef struct OutputStream {
|
||||||
/* stats */
|
/* stats */
|
||||||
// number of packets send to the muxer
|
// number of packets send to the muxer
|
||||||
atomic_uint_least64_t packets_written;
|
atomic_uint_least64_t packets_written;
|
||||||
// number of frames/samples sent to the encoder
|
|
||||||
uint64_t frames_encoded;
|
|
||||||
uint64_t samples_encoded;
|
|
||||||
|
|
||||||
/* packet quality factor */
|
/* packet quality factor */
|
||||||
atomic_int quality;
|
atomic_int quality;
|
||||||
|
|
|
@ -38,8 +38,9 @@
|
||||||
|
|
||||||
#include "libavcodec/avcodec.h"
|
#include "libavcodec/avcodec.h"
|
||||||
|
|
||||||
struct Encoder {
|
typedef struct EncoderPriv {
|
||||||
const AVClass *class;
|
Encoder e;
|
||||||
|
|
||||||
void *log_parent;
|
void *log_parent;
|
||||||
char log_name[32];
|
char log_name[32];
|
||||||
|
|
||||||
|
@ -54,7 +55,12 @@ struct Encoder {
|
||||||
|
|
||||||
Scheduler *sch;
|
Scheduler *sch;
|
||||||
unsigned sch_idx;
|
unsigned sch_idx;
|
||||||
};
|
} EncoderPriv;
|
||||||
|
|
||||||
|
static EncoderPriv *ep_from_enc(Encoder *enc)
|
||||||
|
{
|
||||||
|
return (EncoderPriv*)enc;
|
||||||
|
}
|
||||||
|
|
||||||
// data that is local to the decoder thread and not visible outside of it
|
// data that is local to the decoder thread and not visible outside of it
|
||||||
typedef struct EncoderThread {
|
typedef struct EncoderThread {
|
||||||
|
@ -74,38 +80,38 @@ void enc_free(Encoder **penc)
|
||||||
|
|
||||||
static const char *enc_item_name(void *obj)
|
static const char *enc_item_name(void *obj)
|
||||||
{
|
{
|
||||||
const Encoder *e = obj;
|
const EncoderPriv *ep = obj;
|
||||||
|
|
||||||
return e->log_name;
|
return ep->log_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const AVClass enc_class = {
|
static const AVClass enc_class = {
|
||||||
.class_name = "Encoder",
|
.class_name = "Encoder",
|
||||||
.version = LIBAVUTIL_VERSION_INT,
|
.version = LIBAVUTIL_VERSION_INT,
|
||||||
.parent_log_context_offset = offsetof(Encoder, log_parent),
|
.parent_log_context_offset = offsetof(EncoderPriv, log_parent),
|
||||||
.item_name = enc_item_name,
|
.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, void *log_parent)
|
Scheduler *sch, unsigned sch_idx, void *log_parent)
|
||||||
{
|
{
|
||||||
Encoder *enc;
|
EncoderPriv *ep;
|
||||||
|
|
||||||
*penc = NULL;
|
*penc = NULL;
|
||||||
|
|
||||||
enc = av_mallocz(sizeof(*enc));
|
ep = av_mallocz(sizeof(*ep));
|
||||||
if (!enc)
|
if (!ep)
|
||||||
return AVERROR(ENOMEM);
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
enc->class = &enc_class;
|
ep->e.class = &enc_class;
|
||||||
enc->log_parent = log_parent;
|
ep->log_parent = log_parent;
|
||||||
|
|
||||||
enc->sch = sch;
|
ep->sch = sch;
|
||||||
enc->sch_idx = sch_idx;
|
ep->sch_idx = sch_idx;
|
||||||
|
|
||||||
snprintf(enc->log_name, sizeof(enc->log_name), "enc:%s", codec->name);
|
snprintf(ep->log_name, sizeof(ep->log_name), "enc:%s", codec->name);
|
||||||
|
|
||||||
*penc = enc;
|
*penc = &ep->e;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -166,6 +172,7 @@ int enc_open(void *opaque, const AVFrame *frame)
|
||||||
OutputStream *ost = opaque;
|
OutputStream *ost = opaque;
|
||||||
InputStream *ist = ost->ist;
|
InputStream *ist = ost->ist;
|
||||||
Encoder *e = ost->enc;
|
Encoder *e = ost->enc;
|
||||||
|
EncoderPriv *ep = ep_from_enc(e);
|
||||||
AVCodecContext *enc_ctx = ost->enc_ctx;
|
AVCodecContext *enc_ctx = ost->enc_ctx;
|
||||||
Decoder *dec = NULL;
|
Decoder *dec = NULL;
|
||||||
const AVCodec *enc = enc_ctx->codec;
|
const AVCodec *enc = enc_ctx->codec;
|
||||||
|
@ -174,7 +181,7 @@ int enc_open(void *opaque, const AVFrame *frame)
|
||||||
int frame_samples = 0;
|
int frame_samples = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (e->opened)
|
if (ep->opened)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// frame is always non-NULL for audio and video
|
// frame is always non-NULL for audio and video
|
||||||
|
@ -320,7 +327,7 @@ int enc_open(void *opaque, const AVFrame *frame)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
e->opened = 1;
|
ep->opened = 1;
|
||||||
|
|
||||||
if (enc_ctx->frame_size)
|
if (enc_ctx->frame_size)
|
||||||
frame_samples = enc_ctx->frame_size;
|
frame_samples = enc_ctx->frame_size;
|
||||||
|
@ -352,6 +359,7 @@ static int do_subtitle_out(OutputFile *of, OutputStream *ost, const AVSubtitle *
|
||||||
AVPacket *pkt)
|
AVPacket *pkt)
|
||||||
{
|
{
|
||||||
Encoder *e = ost->enc;
|
Encoder *e = ost->enc;
|
||||||
|
EncoderPriv *ep = ep_from_enc(e);
|
||||||
int subtitle_out_max_size = 1024 * 1024;
|
int subtitle_out_max_size = 1024 * 1024;
|
||||||
int subtitle_out_size, nb, i, ret;
|
int subtitle_out_size, nb, i, ret;
|
||||||
AVCodecContext *enc;
|
AVCodecContext *enc;
|
||||||
|
@ -403,7 +411,7 @@ static int do_subtitle_out(OutputFile *of, OutputStream *ost, const AVSubtitle *
|
||||||
local_sub.rects += i;
|
local_sub.rects += i;
|
||||||
}
|
}
|
||||||
|
|
||||||
ost->frames_encoded++;
|
e->frames_encoded++;
|
||||||
|
|
||||||
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) {
|
||||||
|
@ -425,7 +433,7 @@ static int do_subtitle_out(OutputFile *of, OutputStream *ost, const AVSubtitle *
|
||||||
}
|
}
|
||||||
pkt->dts = pkt->pts;
|
pkt->dts = pkt->pts;
|
||||||
|
|
||||||
ret = sch_enc_send(e->sch, e->sch_idx, pkt);
|
ret = sch_enc_send(ep->sch, ep->sch_idx, pkt);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
av_packet_unref(pkt);
|
av_packet_unref(pkt);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -440,6 +448,7 @@ void enc_stats_write(OutputStream *ost, EncStats *es,
|
||||||
uint64_t frame_num)
|
uint64_t frame_num)
|
||||||
{
|
{
|
||||||
Encoder *e = ost->enc;
|
Encoder *e = ost->enc;
|
||||||
|
EncoderPriv *ep = ep_from_enc(e);
|
||||||
AVIOContext *io = es->io;
|
AVIOContext *io = es->io;
|
||||||
AVRational tb = frame ? frame->time_base : pkt->time_base;
|
AVRational tb = frame ? frame->time_base : pkt->time_base;
|
||||||
int64_t pts = frame ? frame->pts : pkt->pts;
|
int64_t pts = frame ? frame->pts : pkt->pts;
|
||||||
|
@ -477,7 +486,7 @@ void enc_stats_write(OutputStream *ost, EncStats *es,
|
||||||
|
|
||||||
if (frame) {
|
if (frame) {
|
||||||
switch (c->type) {
|
switch (c->type) {
|
||||||
case ENC_STATS_SAMPLE_NUM: avio_printf(io, "%"PRIu64, ost->samples_encoded); continue;
|
case ENC_STATS_SAMPLE_NUM: avio_printf(io, "%"PRIu64, e->samples_encoded); continue;
|
||||||
case ENC_STATS_NB_SAMPLES: avio_printf(io, "%d", frame->nb_samples); continue;
|
case ENC_STATS_NB_SAMPLES: avio_printf(io, "%d", frame->nb_samples); continue;
|
||||||
default: av_assert0(0);
|
default: av_assert0(0);
|
||||||
}
|
}
|
||||||
|
@ -495,7 +504,7 @@ void enc_stats_write(OutputStream *ost, EncStats *es,
|
||||||
}
|
}
|
||||||
case ENC_STATS_AVG_BITRATE: {
|
case ENC_STATS_AVG_BITRATE: {
|
||||||
double duration = pkt->dts * av_q2d(tb);
|
double duration = pkt->dts * av_q2d(tb);
|
||||||
avio_printf(io, "%g", duration > 0 ? 8.0 * e->data_size / duration : -1.);
|
avio_printf(io, "%g", duration > 0 ? 8.0 * ep->data_size / duration : -1.);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
default: av_assert0(0);
|
default: av_assert0(0);
|
||||||
|
@ -515,7 +524,7 @@ static inline double psnr(double d)
|
||||||
|
|
||||||
static int update_video_stats(OutputStream *ost, const AVPacket *pkt, int write_vstats)
|
static int update_video_stats(OutputStream *ost, const AVPacket *pkt, int write_vstats)
|
||||||
{
|
{
|
||||||
Encoder *e = ost->enc;
|
EncoderPriv *ep = ep_from_enc(ost->enc);
|
||||||
const uint8_t *sd = av_packet_get_side_data(pkt, AV_PKT_DATA_QUALITY_STATS,
|
const uint8_t *sd = av_packet_get_side_data(pkt, AV_PKT_DATA_QUALITY_STATS,
|
||||||
NULL);
|
NULL);
|
||||||
AVCodecContext *enc = ost->enc_ctx;
|
AVCodecContext *enc = ost->enc_ctx;
|
||||||
|
@ -549,7 +558,7 @@ static int update_video_stats(OutputStream *ost, const AVPacket *pkt, int write_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
frame_number = e->packets_encoded;
|
frame_number = ep->packets_encoded;
|
||||||
if (vstats_version <= 1) {
|
if (vstats_version <= 1) {
|
||||||
fprintf(vstats_file, "frame= %5"PRId64" q= %2.1f ", frame_number,
|
fprintf(vstats_file, "frame= %5"PRId64" q= %2.1f ", frame_number,
|
||||||
quality / (float)FF_QP2LAMBDA);
|
quality / (float)FF_QP2LAMBDA);
|
||||||
|
@ -569,9 +578,9 @@ static int update_video_stats(OutputStream *ost, const AVPacket *pkt, int write_
|
||||||
ti1 = 0.01;
|
ti1 = 0.01;
|
||||||
|
|
||||||
bitrate = (pkt->size * 8) / av_q2d(enc->time_base) / 1000.0;
|
bitrate = (pkt->size * 8) / av_q2d(enc->time_base) / 1000.0;
|
||||||
avg_bitrate = (double)(e->data_size * 8) / ti1 / 1000.0;
|
avg_bitrate = (double)(ep->data_size * 8) / ti1 / 1000.0;
|
||||||
fprintf(vstats_file, "s_size= %8.0fKiB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s ",
|
fprintf(vstats_file, "s_size= %8.0fKiB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s ",
|
||||||
(double)e->data_size / 1024, ti1, bitrate, avg_bitrate);
|
(double)ep->data_size / 1024, ti1, bitrate, avg_bitrate);
|
||||||
fprintf(vstats_file, "type= %c\n", av_get_picture_type_char(pict_type));
|
fprintf(vstats_file, "type= %c\n", av_get_picture_type_char(pict_type));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -581,6 +590,7 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame,
|
||||||
AVPacket *pkt)
|
AVPacket *pkt)
|
||||||
{
|
{
|
||||||
Encoder *e = ost->enc;
|
Encoder *e = ost->enc;
|
||||||
|
EncoderPriv *ep = ep_from_enc(e);
|
||||||
AVCodecContext *enc = ost->enc_ctx;
|
AVCodecContext *enc = ost->enc_ctx;
|
||||||
const char *type_desc = av_get_media_type_string(enc->codec_type);
|
const char *type_desc = av_get_media_type_string(enc->codec_type);
|
||||||
const char *action = frame ? "encode" : "flush";
|
const char *action = frame ? "encode" : "flush";
|
||||||
|
@ -596,10 +606,10 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame,
|
||||||
|
|
||||||
if (ost->enc_stats_pre.io)
|
if (ost->enc_stats_pre.io)
|
||||||
enc_stats_write(ost, &ost->enc_stats_pre, frame, NULL,
|
enc_stats_write(ost, &ost->enc_stats_pre, frame, NULL,
|
||||||
ost->frames_encoded);
|
e->frames_encoded);
|
||||||
|
|
||||||
ost->frames_encoded++;
|
e->frames_encoded++;
|
||||||
ost->samples_encoded += frame->nb_samples;
|
e->samples_encoded += frame->nb_samples;
|
||||||
|
|
||||||
if (debug_ts) {
|
if (debug_ts) {
|
||||||
av_log(e, AV_LOG_INFO, "encoder <- type:%s "
|
av_log(e, AV_LOG_INFO, "encoder <- type:%s "
|
||||||
|
@ -653,7 +663,7 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame,
|
||||||
|
|
||||||
// attach stream parameters to first packet if requested
|
// attach stream parameters to first packet if requested
|
||||||
avcodec_parameters_free(&fd->par_enc);
|
avcodec_parameters_free(&fd->par_enc);
|
||||||
if (e->attach_par && !e->packets_encoded) {
|
if (ep->attach_par && !ep->packets_encoded) {
|
||||||
fd->par_enc = avcodec_parameters_alloc();
|
fd->par_enc = avcodec_parameters_alloc();
|
||||||
if (!fd->par_enc)
|
if (!fd->par_enc)
|
||||||
return AVERROR(ENOMEM);
|
return AVERROR(ENOMEM);
|
||||||
|
@ -673,7 +683,7 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame,
|
||||||
|
|
||||||
if (ost->enc_stats_post.io)
|
if (ost->enc_stats_post.io)
|
||||||
enc_stats_write(ost, &ost->enc_stats_post, NULL, pkt,
|
enc_stats_write(ost, &ost->enc_stats_post, NULL, pkt,
|
||||||
e->packets_encoded);
|
ep->packets_encoded);
|
||||||
|
|
||||||
if (debug_ts) {
|
if (debug_ts) {
|
||||||
av_log(e, AV_LOG_INFO, "encoder -> type:%s "
|
av_log(e, AV_LOG_INFO, "encoder -> type:%s "
|
||||||
|
@ -685,11 +695,11 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame,
|
||||||
av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, &enc->time_base));
|
av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, &enc->time_base));
|
||||||
}
|
}
|
||||||
|
|
||||||
e->data_size += pkt->size;
|
ep->data_size += pkt->size;
|
||||||
|
|
||||||
e->packets_encoded++;
|
ep->packets_encoded++;
|
||||||
|
|
||||||
ret = sch_enc_send(e->sch, e->sch_idx, pkt);
|
ret = sch_enc_send(ep->sch, ep->sch_idx, pkt);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
av_packet_unref(pkt);
|
av_packet_unref(pkt);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -826,6 +836,7 @@ int encoder_thread(void *arg)
|
||||||
{
|
{
|
||||||
OutputStream *ost = arg;
|
OutputStream *ost = arg;
|
||||||
Encoder *e = ost->enc;
|
Encoder *e = ost->enc;
|
||||||
|
EncoderPriv *ep = ep_from_enc(e);
|
||||||
EncoderThread et;
|
EncoderThread et;
|
||||||
int ret = 0, input_status = 0;
|
int ret = 0, input_status = 0;
|
||||||
int name_set = 0;
|
int name_set = 0;
|
||||||
|
@ -848,11 +859,11 @@ int encoder_thread(void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!input_status) {
|
while (!input_status) {
|
||||||
input_status = sch_enc_receive(e->sch, e->sch_idx, et.frame);
|
input_status = sch_enc_receive(ep->sch, ep->sch_idx, et.frame);
|
||||||
if (input_status < 0) {
|
if (input_status < 0) {
|
||||||
if (input_status == AVERROR_EOF) {
|
if (input_status == AVERROR_EOF) {
|
||||||
av_log(e, AV_LOG_VERBOSE, "Encoder thread received EOF\n");
|
av_log(e, AV_LOG_VERBOSE, "Encoder thread received EOF\n");
|
||||||
if (e->opened)
|
if (ep->opened)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
av_log(e, AV_LOG_ERROR, "Could not open encoder before EOF\n");
|
av_log(e, AV_LOG_ERROR, "Could not open encoder before EOF\n");
|
||||||
|
@ -905,6 +916,7 @@ finish:
|
||||||
|
|
||||||
int enc_loopback(Encoder *enc)
|
int enc_loopback(Encoder *enc)
|
||||||
{
|
{
|
||||||
enc->attach_par = 1;
|
EncoderPriv *ep = ep_from_enc(enc);
|
||||||
return enc->sch_idx;
|
ep->attach_par = 1;
|
||||||
|
return ep->sch_idx;
|
||||||
}
|
}
|
||||||
|
|
|
@ -723,9 +723,9 @@ static void mux_final_stats(Muxer *mux)
|
||||||
of->index, j, av_get_media_type_string(type));
|
of->index, j, av_get_media_type_string(type));
|
||||||
if (ost->enc) {
|
if (ost->enc) {
|
||||||
av_log(of, AV_LOG_VERBOSE, "%"PRIu64" frames encoded",
|
av_log(of, AV_LOG_VERBOSE, "%"PRIu64" frames encoded",
|
||||||
ost->frames_encoded);
|
ost->enc->frames_encoded);
|
||||||
if (type == AVMEDIA_TYPE_AUDIO)
|
if (type == AVMEDIA_TYPE_AUDIO)
|
||||||
av_log(of, AV_LOG_VERBOSE, " (%"PRIu64" samples)", ost->samples_encoded);
|
av_log(of, AV_LOG_VERBOSE, " (%"PRIu64" samples)", ost->enc->samples_encoded);
|
||||||
av_log(of, AV_LOG_VERBOSE, "; ");
|
av_log(of, AV_LOG_VERBOSE, "; ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue