Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
From: Zhao Zhili <quinkblack@foxmail.com>
To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org>
Cc: "Tomas Härdin" <git@haerdin.se>
Subject: Re: [FFmpeg-devel] [PATCH 1/2] lavc/mediacodecenc: Probe supported pixel formats
Date: Sat, 07 Jan 2023 02:03:47 +0800
Message-ID: <tencent_E1E6F8E7EAAA9F5328DC440BACA610909B06@qq.com> (raw)
In-Reply-To: <1a215429e2ac714005e4bc2ccb08c0c3d0bf9356.camel@haerdin.se>

On Fri, 2023-01-06 at 16:42 +0100, Tomas Härdin wrote:


> For each entry in color_formats[] an encoder is configured and opened.
> If this succeeds then the corresponding pixel format is added to probed_pix_fmts[].
> 
> This patch has been released by Epic Games' legal department.
> ---
>  libavcodec/mediacodecenc.c | 76 ++++++++++++++++++++++++++++++++++----
>  1 file changed, 68 insertions(+), 8 deletions(-)
> 
> diff --git a/libavcodec/mediacodecenc.c b/libavcodec/mediacodecenc.c
> index 4c1809093c..fd90d41625 100644
> --- a/libavcodec/mediacodecenc.c
> +++ b/libavcodec/mediacodecenc.c
> @@ -2,6 +2,7 @@
>   * Android MediaCodec encoders
>   *
>   * Copyright (c) 2022 Zhao Zhili <zhilizhao@tencent.com>
> + * Modifications by Epic Games, Inc., 2022.
>   *
>   * This file is part of FFmpeg.
>   *
> @@ -89,12 +90,8 @@ static const struct {
>      { COLOR_FormatSurface,              AV_PIX_FMT_MEDIACODEC },
>  };
>  
> -static const enum AVPixelFormat avc_pix_fmts[] = {
> -    AV_PIX_FMT_MEDIACODEC,
> -    AV_PIX_FMT_YUV420P,
> -    AV_PIX_FMT_NV12,
> -    AV_PIX_FMT_NONE
> -};
> +// filled in by mediacodec_init_static_data()
> +static enum AVPixelFormat probed_pix_fmts[FF_ARRAY_ELEMS(color_formats)+1];
>  
>  static void mediacodec_output_format(AVCodecContext *avctx)
>  {
> @@ -534,6 +531,69 @@ static av_cold int mediacodec_close(AVCodecContext *avctx)
>      return 0;
>  }
>  
> +static av_cold void mediacodec_init_static_data(FFCodec *ffcodec)
> +{
> +    const char *codec_mime = ffcodec->p.id == AV_CODEC_ID_H264 ? "video/avc" : "video/hevc";
> +    FFAMediaCodec *codec;
> +    int num_pix_fmts = 0;
> +    int use_ndk_codec = !av_jni_get_java_vm(NULL);
> +
> +    if (!(codec = ff_AMediaCodec_createEncoderByType(codec_mime, use_ndk_codec))) {
> +        av_log(NULL, AV_LOG_ERROR, "Failed to create encoder for type %s\n", codec_mime);
> +        return;
> +    }
> +
> +    for (int i = 0; i < FF_ARRAY_ELEMS(color_formats); i++) {
> +        if (color_formats[i].pix_fmt == AV_PIX_FMT_MEDIACODEC) {
> +            // assumme AV_PIX_FMT_MEDIACODEC always works
> +            // we don't have a context at this point with which to test it
> +            probed_pix_fmts[num_pix_fmts++] = color_formats[i].pix_fmt;
> +        } else {
> +            FFAMediaFormat *format;
> +            int ret;
> +
> +            if (!(format = ff_AMediaFormat_new(use_ndk_codec))) {
> +                av_log(NULL, AV_LOG_ERROR, "Failed to create media format\n");
> +                ff_AMediaCodec_delete(codec);
> +                continue;

Here is a use-after-free (codec) issue.

> +            }
> +
> +            ff_AMediaFormat_setString(format, "mime", codec_mime);
> +            ff_AMediaFormat_setInt32(format, "width", 1280);
> +            ff_AMediaFormat_setInt32(format, "height", 720);
> +            ff_AMediaFormat_setInt32(format, "color-format", color_formats[i].color_format);
> +            ff_AMediaFormat_setInt32(format, "bitrate", 1000000);
> +            ff_AMediaFormat_setInt32(format, "bitrate-mode", BITRATE_MODE_VBR);
> +            ff_AMediaFormat_setInt32(format, "frame-rate", 30);
> +            ff_AMediaFormat_setInt32(format, "i-frame-interval", 1);
> +
> +            // no need to set profile, level or number of B-frames it seems
> +            ret = ff_AMediaCodec_getConfigureFlagEncode(codec);
> +            ret = ff_AMediaCodec_configure(codec, format, NULL, NULL, ret);
> +            if (ret) {
> +                av_log(NULL, AV_LOG_ERROR, "MediaCodec configure failed, %s\n", av_err2str(ret));
> +                goto bailout;
> +            }
> +
> +            ret = ff_AMediaCodec_start(codec);
> +            if (ret) {
> +                av_log(NULL, AV_LOG_ERROR, "MediaCodec failed to start, %s\n", av_err2str(ret));
> +                goto bailout;
> +            }
> +            ff_AMediaCodec_stop(codec);
> +
> +            probed_pix_fmts[num_pix_fmts++] = color_formats[i].pix_fmt;
> +        bailout:
> +            // format is never NULL here
> +            ff_AMediaFormat_delete(format);
> +        }
> +    }
> +
> +    probed_pix_fmts[num_pix_fmts] = AV_PIX_FMT_NONE;
> +    ffcodec->p.pix_fmts = probed_pix_fmts;
> +    ff_AMediaCodec_delete(codec);
> +}
> +
>  static const AVCodecHWConfigInternal *const mediacodec_hw_configs[] = {
>      &(const AVCodecHWConfigInternal) {
>          .public          = {
> @@ -579,7 +639,7 @@ static const AVClass name ## _mediacodec_class = {  \
>  
>  #define DECLARE_MEDIACODEC_ENCODER(short_name, long_name, codec_id)     \
>  MEDIACODEC_ENCODER_CLASS(short_name)                                    \
> -const FFCodec ff_ ## short_name ## _mediacodec_encoder = {              \
> +FFCodec ff_ ## short_name ## _mediacodec_encoder = {              \
>      .p.name           = #short_name "_mediacodec",                      \
>      CODEC_LONG_NAME(long_name " Android MediaCodec encoder"),           \
>      .p.type           = AVMEDIA_TYPE_VIDEO,                             \
> @@ -587,7 +647,6 @@ const FFCodec ff_ ## short_name ## _mediacodec_encoder = {              \
>      .p.capabilities   = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY           \
>                          | AV_CODEC_CAP_HARDWARE,                        \
>      .priv_data_size   = sizeof(MediaCodecEncContext),                   \
> -    .p.pix_fmts       = avc_pix_fmts,                                   \
>      .init             = mediacodec_init,                                \
>      FF_CODEC_RECEIVE_PACKET_CB(mediacodec_encode),                      \
>      .close            = mediacodec_close,                               \
> @@ -595,6 +654,7 @@ const FFCodec ff_ ## short_name ## _mediacodec_encoder = {              \
>      .caps_internal    = FF_CODEC_CAP_INIT_CLEANUP,                      \
>      .p.wrapper_name = "mediacodec",                                     \
>      .hw_configs     = mediacodec_hw_configs,                            \
> +    .init_static_data = mediacodec_init_static_data,                    \
>  };                                                                      \
>  
>  #if CONFIG_H264_MEDIACODEC_ENCODER
> -- 
> 2.30.2
> 

init_static_data should be determinate, no matter when it was called, it should
give the same result. In addition to the 'different MediaCodec backends support
different pixel format' issue, another concern of this method is that it's not
determinate, it can give different results at different time/condition.

MediaCodec can fail for all kinds of reasons, and it can fail dynamically. For
example, the supported instance is limited (getMaxSupportedInstances()). Some
low end/legacy chip only support one instance. So it can fail when another app
or another SDK in the same app has already created a codec instance. It can
fail when out of other resouce (like GPU memory) temporarily. Since
init_static_data() only being called once, there is no way to recover from a
temporary failure.

If there is no other reason, stick to AV_PIX_FMT_MEDIACODEC/AV_PIX_FMT_NV12
should be safe.

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

  parent reply	other threads:[~2023-01-06 18:04 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-01-06 15:42 Tomas Härdin
2023-01-06 15:43 ` [FFmpeg-devel] [PATCH 2/2] lavc/mediacodecenc: Probe actually supported color formats using JNI Tomas Härdin
2023-01-06 18:03 ` Zhao Zhili [this message]
2023-01-06 18:21   ` [FFmpeg-devel] [PATCH 1/2] lavc/mediacodecenc: Probe supported pixel formats Tomas Härdin
2023-01-07  5:02     ` Zhao Zhili
2023-01-09 12:27       ` Tomas Härdin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=tencent_E1E6F8E7EAAA9F5328DC440BACA610909B06@qq.com \
    --to=quinkblack@foxmail.com \
    --cc=ffmpeg-devel@ffmpeg.org \
    --cc=git@haerdin.se \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git