[FFmpeg-devel] [PATCH 2/4] avcodec/encode: restructure the core encoding code
Anton Khirnov
anton at khirnov.net
Wed Mar 11 12:18:40 EET 2020
Quoting James Almer (2020-02-27 19:02:00)
> This commit follows the same logic as 061a0c14bb, but for the encode API: The
> new public encoding API will no longer be a wrapper around the old deprecated
> one, and the internal API used by the encoders now consists of a single
> receive_packet() callback that pulls frames as required.
>
> Signed-off-by: James Almer <jamrial at gmail.com>
> ---
> libavcodec/avcodec.h | 12 +-
> libavcodec/encode.c | 268 ++++++++++++++++++++++++++++++++----------
> libavcodec/encode.h | 39 ++++++
> libavcodec/internal.h | 7 +-
> libavcodec/utils.c | 12 +-
> 5 files changed, 268 insertions(+), 70 deletions(-)
> create mode 100644 libavcodec/encode.h
>
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> +static int encode_simple_internal(AVCodecContext *avctx, AVPacket *avpkt)
> +{
> + AVCodecInternal *avci = avctx->internal;
> + EncodeSimpleContext *es = &avci->es;
> + AVFrame *frame = es->in_frame;
> + AVFrame *padded_frame = NULL;
> + int got_packet;
> int ret;
> - *got_packet = 0;
>
> - av_packet_unref(avctx->internal->buffer_pkt);
> - avctx->internal->buffer_pkt_valid = 0;
> + if (!frame->buf[0] && !avci->draining) {
> + av_frame_unref(frame);
> + ret = ff_encode_get_frame(avctx, frame);
> + if (ret < 0 && ret != AVERROR_EOF)
> + return ret;
> + }
>
> - if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
> - ret = avcodec_encode_video2(avctx, avctx->internal->buffer_pkt,
> - frame, got_packet);
> - } else if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
> - ret = avcodec_encode_audio2(avctx, avctx->internal->buffer_pkt,
> - frame, got_packet);
> - } else {
> - ret = AVERROR(EINVAL);
> + if (avci->draining_done)
> + return AVERROR_EOF;
nit: this check would be better at the top of the function, since it
shouldn't interact with the block above
> +
> + if (!frame->buf[0]) {
> + if (!(avctx->codec->capabilities & AV_CODEC_CAP_DELAY ||
> + avctx->active_thread_type & FF_THREAD_FRAME))
> + return AVERROR_EOF;
> +
> + // Flushing is signaled with a NULL frame
> + frame = NULL;
> + }
> +
> + got_packet = 0;
> +
> + if (avctx->codec->type == AVMEDIA_TYPE_VIDEO) {
> + if ((avctx->flags & AV_CODEC_FLAG_PASS1) && avctx->stats_out)
> + avctx->stats_out[0] = '\0';
> +
> + if (av_image_check_size2(avctx->width, avctx->height, avctx->max_pixels, AV_PIX_FMT_NONE, 0, avctx)) {
> + ret = AVERROR(EINVAL);
> + goto end;
> + }
> + if (frame) {
> + if (frame->format == AV_PIX_FMT_NONE)
> + av_log(avctx, AV_LOG_WARNING, "AVFrame.format is not set\n");
> + if (frame->width == 0 || frame->height == 0)
> + av_log(avctx, AV_LOG_WARNING, "AVFrame.width or height is not set\n");
> + }
> + } else if (frame && avctx->codec->type == AVMEDIA_TYPE_AUDIO) {
> + /* extract audio service type metadata */
> + AVFrameSideData *sd = av_frame_get_side_data(frame, AV_FRAME_DATA_AUDIO_SERVICE_TYPE);
> + if (sd && sd->size >= sizeof(enum AVAudioServiceType))
> + avctx->audio_service_type = *(enum AVAudioServiceType*)sd->data;
> +
> + /* check for valid frame size */
> + if (avctx->codec->capabilities & AV_CODEC_CAP_SMALL_LAST_FRAME) {
> + if (frame->nb_samples > avctx->frame_size) {
> + av_log(avctx, AV_LOG_ERROR, "more samples than frame size (avcodec_encode_audio2)\n");
> + ret = AVERROR(EINVAL);
> + goto end;
> + }
> + } else if (!(avctx->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE)) {
> + /* if we already got an undersized frame, that must have been the last */
> + if (avctx->internal->last_audio_frame) {
> + av_log(avctx, AV_LOG_ERROR, "frame_size (%d) was not respected for a non-last frame (avcodec_encode_audio2)\n", avctx->frame_size);
> + ret = AVERROR(EINVAL);
> + goto end;
> + }
> +
> + if (frame->nb_samples < avctx->frame_size) {
> + ret = pad_last_frame(avctx, &padded_frame, frame);
> + if (ret < 0)
> + goto end;
> +
> + av_frame_unref(frame);
> + frame = padded_frame;
> + avctx->internal->last_audio_frame = 1;
> + }
> +
> + if (frame->nb_samples != avctx->frame_size) {
> + av_log(avctx, AV_LOG_ERROR, "nb_samples (%d) != frame_size (%d) (avcodec_encode_audio2)\n", frame->nb_samples, avctx->frame_size);
> + ret = AVERROR(EINVAL);
> + goto end;
> + }
> + }
> + }
Nothing about this block looks specific to the simple encoding API. Some
of those should be in the avcodec_send_frame(), others could possibly be
dropped.
--
Anton Khirnov
More information about the ffmpeg-devel
mailing list