[FFmpeg-devel] [PATCH 10/12] avcodec: add MediaCodec encoder
"zhilizhao(赵志立)"
quinkblack at foxmail.com
Mon Nov 21 06:40:28 EET 2022
> On Nov 21, 2022, at 07:44, Aman Karmani <ffmpeg at tmm1.net> wrote:
>
> On Sat, Nov 19, 2022 at 9:13 AM "zhilizhao(赵志立)" <quinkblack at foxmail.com>
> wrote:
>
>>
>>
>>> On Nov 19, 2022, at 17:15, Aman Karmani <aman at tmm1.net> wrote:
>>>
>>>
>>>
>>> On Sun, Oct 23, 2022 at 8:17 PM Zhao Zhili <quinkblack at foxmail.com>
>> wrote:
>>> From: Zhao Zhili <zhilizhao at tencent.com>
>>>
>>> Signed-off-by: Zhao Zhili <zhilizhao at tencent.com>
>>> ---
>>> Changelog | 1 +
>>> configure | 4 +
>>> libavcodec/Makefile | 2 +
>>> libavcodec/allcodecs.c | 2 +
>>> libavcodec/mediacodec_wrapper.c | 102 ++++++-
>>> libavcodec/mediacodec_wrapper.h | 8 +
>>> libavcodec/mediacodecenc.c | 495 ++++++++++++++++++++++++++++++++
>>> libavcodec/version.h | 4 +-
>>> 8 files changed, 611 insertions(+), 7 deletions(-)
>>> create mode 100644 libavcodec/mediacodecenc.c
>>>
>>> diff --git a/Changelog b/Changelog
>>> index 9e203833aa..9e39a35972 100644
>>> --- a/Changelog
>>> +++ b/Changelog
>>> @@ -19,6 +19,7 @@ version <next>:
>>> - DTS to PTS reorder bsf
>>> - ViewQuest VQC decoder
>>> - MediaCodec decoder via NDKMediaCodec
>>> +- MediaCodec encoder
>>>
>>>
>>>
>>> version 5.1:
>>> diff --git a/configure b/configure
>>> index ee2e3ba6ac..5114cda13f 100755
>>> --- a/configure
>>> +++ b/configure
>>> @@ -3193,6 +3193,8 @@ h264_cuvid_decoder_select="h264_mp4toannexb_bsf"
>>> h264_mediacodec_decoder_deps="mediacodec"
>>> h264_mediacodec_decoder_extralibs="-landroid"
>>> h264_mediacodec_decoder_select="h264_mp4toannexb_bsf h264_parser"
>>> +h264_mediacodec_encoder_deps="mediacodec"
>>> +h264_mediacodec_encoder_extralibs="-landroid"
>>> h264_mf_encoder_deps="mediafoundation"
>>> h264_mmal_decoder_deps="mmal"
>>> h264_nvenc_encoder_deps="nvenc"
>>> @@ -3212,6 +3214,8 @@ hevc_cuvid_decoder_select="hevc_mp4toannexb_bsf"
>>> hevc_mediacodec_decoder_deps="mediacodec"
>>> hevc_mediacodec_decoder_extralibs="-landroid"
>>> hevc_mediacodec_decoder_select="hevc_mp4toannexb_bsf hevc_parser"
>>> +hevc_mediacodec_encoder_deps="mediacodec"
>>> +hevc_mediacodec_encoder_extralibs="-landroid"
>>> hevc_mf_encoder_deps="mediafoundation"
>>> hevc_nvenc_encoder_deps="nvenc"
>>> hevc_nvenc_encoder_select="atsc_a53"
>>> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
>>> index 90c7f113a3..7d0b513eec 100644
>>> --- a/libavcodec/Makefile
>>> +++ b/libavcodec/Makefile
>>> @@ -393,6 +393,7 @@ OBJS-$(CONFIG_H264_DECODER) += h264dec.o
>> h264_cabac.o h264_cavlc.o \
>>> OBJS-$(CONFIG_H264_AMF_ENCODER) += amfenc_h264.o
>>> OBJS-$(CONFIG_H264_CUVID_DECODER) += cuviddec.o
>>> OBJS-$(CONFIG_H264_MEDIACODEC_DECODER) += mediacodecdec.o
>>> +OBJS-$(CONFIG_H264_MEDIACODEC_ENCODER) += mediacodecenc.o
>>> OBJS-$(CONFIG_H264_MF_ENCODER) += mfenc.o mf_utils.o
>>> OBJS-$(CONFIG_H264_MMAL_DECODER) += mmaldec.o
>>> OBJS-$(CONFIG_H264_NVENC_ENCODER) += nvenc_h264.o nvenc.o
>>> @@ -417,6 +418,7 @@ OBJS-$(CONFIG_HEVC_DECODER) += hevcdec.o
>> hevc_mvs.o \
>>> OBJS-$(CONFIG_HEVC_AMF_ENCODER) += amfenc_hevc.o
>>> OBJS-$(CONFIG_HEVC_CUVID_DECODER) += cuviddec.o
>>> OBJS-$(CONFIG_HEVC_MEDIACODEC_DECODER) += mediacodecdec.o
>>> +OBJS-$(CONFIG_HEVC_MEDIACODEC_ENCODER) += mediacodecenc.o
>>> OBJS-$(CONFIG_HEVC_MF_ENCODER) += mfenc.o mf_utils.o
>>> OBJS-$(CONFIG_HEVC_NVENC_ENCODER) += nvenc_hevc.o nvenc.o
>>> OBJS-$(CONFIG_HEVC_QSV_DECODER) += qsvdec.o
>>> diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
>>> index 46ad3b5a25..4c33a9ec3c 100644
>>> --- a/libavcodec/allcodecs.c
>>> +++ b/libavcodec/allcodecs.c
>>> @@ -154,6 +154,7 @@ extern const FFCodec ff_h264_decoder;
>>> extern const FFCodec ff_h264_crystalhd_decoder;
>>> extern const FFCodec ff_h264_v4l2m2m_decoder;
>>> extern const FFCodec ff_h264_mediacodec_decoder;
>>> +extern const FFCodec ff_h264_mediacodec_encoder;
>>> extern const FFCodec ff_h264_mmal_decoder;
>>> extern const FFCodec ff_h264_qsv_decoder;
>>> extern const FFCodec ff_h264_rkmpp_decoder;
>>> @@ -842,6 +843,7 @@ extern const FFCodec ff_h264_videotoolbox_encoder;
>>> extern const FFCodec ff_hevc_amf_encoder;
>>> extern const FFCodec ff_hevc_cuvid_decoder;
>>> extern const FFCodec ff_hevc_mediacodec_decoder;
>>> +extern const FFCodec ff_hevc_mediacodec_encoder;
>>> extern const FFCodec ff_hevc_mf_encoder;
>>> extern const FFCodec ff_hevc_nvenc_encoder;
>>> extern const FFCodec ff_hevc_qsv_encoder;
>>> diff --git a/libavcodec/mediacodec_wrapper.c
>> b/libavcodec/mediacodec_wrapper.c
>>> index 284d615980..5d1a32031d 100644
>>> --- a/libavcodec/mediacodec_wrapper.c
>>> +++ b/libavcodec/mediacodec_wrapper.c
>>> @@ -212,6 +212,9 @@ struct JNIAMediaCodecFields {
>>> jmethodID release_output_buffer_id;
>>> jmethodID release_output_buffer_at_time_id;
>>>
>>> + jmethodID set_input_surface_id;
>>> + jmethodID signal_end_of_input_stream_id;
>>> +
>>> jclass mediainfo_class;
>>>
>>> jmethodID init_id;
>>> @@ -261,6 +264,9 @@ static const struct FFJniField
>> jni_amediacodec_mapping[] = {
>>> { "android/media/MediaCodec", "releaseOutputBuffer", "(IZ)V",
>> FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields,
>> release_output_buffer_id), 1 },
>>> { "android/media/MediaCodec", "releaseOutputBuffer", "(IJ)V",
>> FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields,
>> release_output_buffer_at_time_id), 0 },
>>>
>>> + { "android/media/MediaCodec", "setInputSurface",
>> "(Landroid/view/Surface;)V", FF_JNI_METHOD, offsetof(struct
>> JNIAMediaCodecFields, set_input_surface_id), 0 },
>>> + { "android/media/MediaCodec", "signalEndOfInputStream", "()V",
>> FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields,
>> signal_end_of_input_stream_id), 0 },
>>> +
>>> { "android/media/MediaCodec$BufferInfo", NULL, NULL, FF_JNI_CLASS,
>> offsetof(struct JNIAMediaCodecFields, mediainfo_class), 1 },
>>>
>>> { "android/media/MediaCodec.BufferInfo", "<init>", "()V",
>> FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, init_id), 1 },
>>> @@ -1385,7 +1391,26 @@ static int mediacodec_jni_configure(FFAMediaCodec
>> *ctx,
>>>
>>> JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
>>>
>>> - (*env)->CallVoidMethod(env, codec->object,
>> codec->jfields.configure_id, format->object, surface, NULL, flags);
>>> + if (flags & codec->CONFIGURE_FLAG_ENCODE) {
>>> + if (surface && !codec->jfields.set_input_surface_id) {
>>> + av_log(ctx, AV_LOG_ERROR, "System doesn't support
>> setInputSurface\n");
>>> + return AVERROR_EXTERNAL;
>>> + }
>>> +
>>> + (*env)->CallVoidMethod(env, codec->object,
>> codec->jfields.configure_id, format->object, NULL, NULL, flags);
>>> + if (ff_jni_exception_check(env, 1, codec) < 0)
>>> + return AVERROR_EXTERNAL;
>>> +
>>> + if (!surface)
>>> + return 0;
>>> +
>>> + (*env)->CallVoidMethod(env, codec->object,
>> codec->jfields.set_input_surface_id, surface);
>>> + if (ff_jni_exception_check(env, 1, codec) < 0)
>>> + return AVERROR_EXTERNAL;
>>> + return 0;
>>> + } else {
>>> + (*env)->CallVoidMethod(env, codec->object,
>> codec->jfields.configure_id, format->object, surface, NULL, flags);
>>> + }
>>> if (ff_jni_exception_check(env, 1, codec) < 0) {
>>> ret = AVERROR_EXTERNAL;
>>> goto fail;
>>> @@ -1743,6 +1768,22 @@ fail:
>>> return ret;
>>> }
>>>
>>> +static int mediacodec_jni_signalEndOfInputStream(FFAMediaCodec *ctx)
>>> +{
>>> + int ret = 0;
>>> + JNIEnv *env = NULL;
>>> + FFAMediaCodecJni *codec = (FFAMediaCodecJni *)ctx;
>>> +
>>> + JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
>>> +
>>> + (*env)->CallVoidMethod(env, codec->object,
>> codec->jfields.signal_end_of_input_stream_id);
>>> + if (ff_jni_exception_check(env, 1, codec) < 0) {
>>> + return AVERROR_EXTERNAL;
>>> + }
>>> +
>>> + return 0;
>>> +}
>>> +
>>> static const FFAMediaFormat media_format_jni = {
>>> .class = &amediaformat_class,
>>>
>>> @@ -1801,6 +1842,7 @@ static const FFAMediaCodec media_codec_jni = {
>>>
>>> .getConfigureFlagEncode = mediacodec_jni_getConfigureFlagEncode,
>>> .cleanOutputBuffers = mediacodec_jni_cleanOutputBuffers,
>>> + .signalEndOfInputStream = mediacodec_jni_signalEndOfInputStream,
>>> };
>>>
>>> typedef struct FFAMediaFormatNdk {
>>> @@ -1866,6 +1908,10 @@ typedef struct FFAMediaCodecNdk {
>>> // Available since API level 28.
>>> media_status_t (*getName)(AMediaCodec*, char** out_name);
>>> void (*releaseName)(AMediaCodec*, char* name);
>>> +
>>> + // Available since API level 26.
>>> + media_status_t (*setInputSurface)(AMediaCodec*, ANativeWindow *);
>>> + media_status_t (*signalEndOfInputStream)(AMediaCodec *);
>>> } FFAMediaCodecNdk;
>>>
>>> static const FFAMediaFormat media_format_ndk;
>>> @@ -2098,6 +2144,9 @@ static inline FFAMediaCodec *ndk_codec_create(int
>> method, const char *arg) {
>>> GET_SYMBOL(getName, 0)
>>> GET_SYMBOL(releaseName, 0)
>>>
>>> + GET_SYMBOL(setInputSurface, 0)
>>> + GET_SYMBOL(signalEndOfInputStream, 0)
>>> +
>>> #undef GET_SYMBOL
>>>
>>> switch (method) {
>>> @@ -2184,10 +2233,32 @@ static int
>> mediacodec_ndk_configure(FFAMediaCodec* ctx,
>>> return AVERROR(EINVAL);
>>> }
>>>
>>> - status = codec->configure(codec->impl, format->impl, native_window,
>> NULL, flags);
>>> - if (status != AMEDIA_OK) {
>>> - av_log(codec, AV_LOG_ERROR, "configure failed, %d\n", status);
>>> - return AVERROR_EXTERNAL;
>>> + if (flags & AMEDIACODEC_CONFIGURE_FLAG_ENCODE) {
>>> + if (native_window && !codec->setInputSurface) {
>>> + av_log(ctx, AV_LOG_ERROR, "System doesn't support
>> setInputSurface\n");
>>> + return AVERROR_EXTERNAL;
>>> + }
>>> +
>>> + status = codec->configure(codec->impl, format->impl, NULL,
>> NULL, flags);
>>> + if (status != AMEDIA_OK) {
>>> + av_log(codec, AV_LOG_ERROR, "Encoder configure failed,
>> %d\n", status);
>>> + return AVERROR_EXTERNAL;
>>> + }
>>> +
>>> + if (!native_window)
>>> + return 0;
>>> +
>>> + status = codec->setInputSurface(codec->impl, native_window);
>>> + if (status != AMEDIA_OK) {
>>> + av_log(codec, AV_LOG_ERROR, "Encoder set input surface
>> failed, %d\n", status);
>>> + return AVERROR_EXTERNAL;
>>> + }
>>> + } else {
>>> + status = codec->configure(codec->impl, format->impl,
>> native_window, NULL, flags);
>>> + if (status != AMEDIA_OK) {
>>> + av_log(codec, AV_LOG_ERROR, "Decoder configure failed,
>> %d\n", status);
>>> + return AVERROR_EXTERNAL;
>>> + }
>>> }
>>>
>>> return 0;
>>> @@ -2330,6 +2401,26 @@ static int
>> mediacodec_ndk_cleanOutputBuffers(FFAMediaCodec *ctx)
>>> return 0;
>>> }
>>>
>>> +static int mediacodec_ndk_signalEndOfInputStream(FFAMediaCodec *ctx)
>>> +{
>>> + FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx;
>>> + media_status_t status;
>>> +
>>> + if (!codec->signalEndOfInputStream) {
>>> + av_log(codec, AV_LOG_ERROR, "signalEndOfInputStream
>> unavailable\n");
>>> + return AVERROR_EXTERNAL;
>>> + }
>>> +
>>> + status = codec->signalEndOfInputStream(codec->impl);
>>> + if (status != AMEDIA_OK) {
>>> + av_log(codec, AV_LOG_ERROR, "signalEndOfInputStream failed,
>> %d\n", status);
>>> + return AVERROR_EXTERNAL;
>>> + }
>>> + av_log(codec, AV_LOG_DEBUG, "signalEndOfInputStream success\n");
>>> +
>>> + return 0;
>>> +}
>>> +
>>> static const FFAMediaFormat media_format_ndk = {
>>> .class = &amediaformat_ndk_class,
>>>
>>> @@ -2388,6 +2479,7 @@ static const FFAMediaCodec media_codec_ndk = {
>>>
>>> .getConfigureFlagEncode = mediacodec_ndk_getConfigureFlagEncode,
>>> .cleanOutputBuffers = mediacodec_ndk_cleanOutputBuffers,
>>> + .signalEndOfInputStream = mediacodec_ndk_signalEndOfInputStream,
>>> };
>>>
>>> FFAMediaFormat *ff_AMediaFormat_new(int ndk)
>>> diff --git a/libavcodec/mediacodec_wrapper.h
>> b/libavcodec/mediacodec_wrapper.h
>>> index 7cf3f4aecd..f15ad66d83 100644
>>> --- a/libavcodec/mediacodec_wrapper.h
>>> +++ b/libavcodec/mediacodec_wrapper.h
>>> @@ -192,6 +192,9 @@ struct FFAMediaCodec {
>>> int (*getConfigureFlagEncode)(FFAMediaCodec *codec);
>>>
>>> int (*cleanOutputBuffers)(FFAMediaCodec *codec);
>>> +
>>> + // For encoder with FFANativeWindow as input.
>>> + int (*signalEndOfInputStream)(FFAMediaCodec *);
>>> };
>>>
>>> static inline char *ff_AMediaCodec_getName(FFAMediaCodec *codec)
>>> @@ -311,6 +314,11 @@ static inline int
>> ff_AMediaCodec_cleanOutputBuffers(FFAMediaCodec *codec)
>>> return codec->cleanOutputBuffers(codec);
>>> }
>>>
>>> +static inline int ff_AMediaCodec_signalEndOfInputStream(FFAMediaCodec
>> *codec)
>>> +{
>>> + return codec->signalEndOfInputStream(codec);
>>> +}
>>> +
>>> int ff_Build_SDK_INT(AVCodecContext *avctx);
>>>
>>> #endif /* AVCODEC_MEDIACODEC_WRAPPER_H */
>>> diff --git a/libavcodec/mediacodecenc.c b/libavcodec/mediacodecenc.c
>>> new file mode 100644
>>> index 0000000000..c81050ec80
>>> --- /dev/null
>>> +++ b/libavcodec/mediacodecenc.c
>>> @@ -0,0 +1,495 @@
>>> +/*
>>> + * Android MediaCodec encoders
>>> + *
>>> + * Copyright (c) 2022 Zhao Zhili <zhilizhao at tencent.com>
>>> + *
>>> + * This file is part of FFmpeg.
>>> + *
>>> + * FFmpeg is free software; you can redistribute it and/or
>>> + * modify it under the terms of the GNU Lesser General Public
>>> + * License as published by the Free Software Foundation; either
>>> + * version 2.1 of the License, or (at your option) any later version.
>>> + *
>>> + * FFmpeg is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>>> + * Lesser General Public License for more details.
>>> + *
>>> + * You should have received a copy of the GNU Lesser General Public
>>> + * License along with FFmpeg; if not, write to the Free Software
>>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
>> 02110-1301 USA
>>> + */
>>> +
>>> +#include "config_components.h"
>>> +
>>> +#include "libavutil/avassert.h"
>>> +#include "libavutil/hwcontext_mediacodec.h"
>>> +#include "libavutil/imgutils.h"
>>> +#include "libavutil/opt.h"
>>> +
>>> +#include "avcodec.h"
>>> +#include "codec_internal.h"
>>> +#include "encode.h"
>>> +#include "hwconfig.h"
>>> +#include "jni.h"
>>> +#include "mediacodec.h"
>>> +#include "mediacodec_wrapper.h"
>>> +#include "mediacodecdec_common.h"
>>> +
>>> +#define INPUT_DEQUEUE_TIMEOUT_US 8000
>>> +#define OUTPUT_DEQUEUE_TIMEOUT_US 8000
>>> +
>>> +typedef struct MediaCodecEncContext {
>>> + AVClass *avclass;
>>> + FFAMediaCodec *codec;
>>> + int use_ndk_codec;
>>> + FFANativeWindow *window;
>>> +
>>> + int fps;
>>> + int width;
>>> + int height;
>>> +
>>> + uint8_t *extradata;
>>> + int extradata_size;
>>> +
>>> + // Since MediaCodec doesn't output DTS, use a timestamp queue to
>> save pts
>>> + // of AVFrame and generate DTS for AVPacket.
>>> + //
>>> + // This doesn't work when use Surface as input, in that case frames
>> can be
>>> + // sent to encoder without our notice. One exception is frames come
>> from
>>> + // our MediaCodec decoder wrapper, since we can control it's render
>> by
>>> + // av_mediacodec_release_buffer.
>>> + int64_t timestamps[32];
>>> + int ts_head;
>>> + int ts_tail;
>>> +
>>> + int eof_sent;
>>> +
>>> + AVFrame *frame;
>>> +} MediaCodecEncContext;
>>> +
>>> +enum {
>>> + COLOR_FormatYUV420Planar = 0x13,
>>> + COLOR_FormatYUV420SemiPlanar = 0x15,
>>> + COLOR_FormatSurface = 0x7F000789,
>>> +};
>>> +
>>> +static const struct {
>>> + int color_format;
>>> + enum AVPixelFormat pix_fmt;
>>> +} color_formats[] = {
>>> + { COLOR_FormatYUV420Planar, AV_PIX_FMT_YUV420P },
>>> + { COLOR_FormatYUV420SemiPlanar, AV_PIX_FMT_NV12 },
>>> + { 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
>>> +};
>>> +
>>> +static void mediacodec_output_format(AVCodecContext *avctx)
>>> +{
>>> + MediaCodecEncContext *s = avctx->priv_data;
>>> + char *name = ff_AMediaCodec_getName(s->codec);
>>> + FFAMediaFormat *out_format =
>> ff_AMediaCodec_getOutputFormat(s->codec);
>>> + char *str = ff_AMediaFormat_toString(out_format);
>>> +
>>> + av_log(avctx, AV_LOG_DEBUG, "MediaCodec encoder %s output format
>> %s\n",
>>> + name ? name : "unknown", str);
>>> + av_free(name);
>>> + av_free(str);
>>> + ff_AMediaFormat_delete(out_format);
>>> +}
>>> +
>>> +static av_cold int mediacodec_init(AVCodecContext *avctx)
>>> +{
>>> + const char *codec_mime = NULL;
>>> + MediaCodecEncContext *s = avctx->priv_data;
>>> + FFAMediaFormat *format = NULL;
>>> + int ret;
>>> + int gop;
>>> +
>>> + if (s->use_ndk_codec < 0)
>>> + s->use_ndk_codec = !av_jni_get_java_vm(avctx);
>>> +
>>> + switch (avctx->codec_id) {
>>> + case AV_CODEC_ID_H264:
>>> + codec_mime = "video/avc";
>>> + break;
>>> + case AV_CODEC_ID_HEVC:
>>> + codec_mime = "video/hevc";
>>> + break;
>>> + default:
>>> + av_assert0(0);
>>> + }
>>> +
>>> + s->codec = ff_AMediaCodec_createEncoderByType(codec_mime,
>> s->use_ndk_codec);
>>> + if (!s->codec) {
>>> + av_log(avctx, AV_LOG_ERROR, "Failed to create encoder for type
>> %s\n",
>>> + codec_mime);
>>> + return AVERROR_EXTERNAL;
>>> + }
>>> +
>>> + format = ff_AMediaFormat_new(s->use_ndk_codec);
>>> + if (!format) {
>>> + av_log(avctx, AV_LOG_ERROR, "Failed to create media format\n");
>>> + return AVERROR_EXTERNAL;
>>> + }
>>> +
>>> + ff_AMediaFormat_setString(format, "mime", codec_mime);
>>> + s->width = FFALIGN(avctx->width, 16);
>>> + s->height = avctx->height;
>>> + ff_AMediaFormat_setInt32(format, "width", s->width);
>>> + ff_AMediaFormat_setInt32(format, "height", s->height);
>>>
>>> Is it preferable to use constants like AMEDIAFORMAT_KEY_HEIGHT here?
>>>
>>> I don't have a preference either way.
>>
>> These KEYs aren’t string literal, they are global variables.
>>
>> extern const char* AMEDIAFORMAT_KEY_HEIGHT __INTRODUCED_IN(21);
>>
>> Some basic ones are introduced very late, e.g.,
>>
>> extern const char* AMEDIAFORMAT_KEY_CSD __INTRODUCED_IN(28);
>> extern const char* AMEDIAFORMAT_KEY_CSD_0 __INTRODUCED_IN(28);
>> extern const char* AMEDIAFORMAT_KEY_CSD_1 __INTRODUCED_IN(28);
>> extern const char* AMEDIAFORMAT_KEY_CSD_2 __INTRODUCED_IN(28);
>> extern const char* AMEDIAFORMAT_KEY_DISPLAY_CROP __INTRODUCED_IN(28);
>>
>> So we can’t use these AMEDIAFORMAT_KEY_ directly. dlsym() these global
>> variables and with a fallback value is possible, just over-engineering.
>>
>> Google’s API design forced us to use string literal directly.
>>
>>>
>>> It may be worth also passing in the same values to
>> AMEDIAFORMAT_KEY_MAX_WIDTH and AMEDIAFORMAT_KEY_MAX_HEIGHT
>>
>> The documentation hints they are for decoder only:
>>
>>> A key describing the maximum expected width of the content in a video
>> decoder format, in case there are resolution changes in the video content.
>>
>> https://developer.android.com/reference/android/media/MediaFormat
>>
>>>
>>> And I think the unaligned width should be set into
>> AMEDIAFORMAT_KEY_STRIDE
>>
>> Technically, KEY_WIDTH should be unaligned width, and KEY_STRIDE should
>> be aligned width. However,
>>
>> 1. It’s well known that a lot of devices can’t handle width doesn’t aligned
>> to 16, they will crash, report error or produce broken files.
>>
>> 2. CTS tests only verify that 16 aligned resolutions are supported.
>>
>> 3. There are alignment info in OMX and exported via MediaCodecInfo, like
>>
>> <MediaCodec name="c2.qti.avc.encoder" type="video/avc">
>> <Alias name="OMX.qcom.video.encoder.avc" />
>> <Limit name="size" min="96x96" max="4096x2304" />
>> <Limit name="alignment" value="2x2" />
>> <Limit name="block-size" value="16x16" />
>>
>> It can be missing on old devices, or worse, the info doesn’t reflect the
>> real requirement (Maybe it was just a copy-paste from some places).
>>
>> I have an idea to fix the issue: always encoding in aligned resolution,
>> then fix the crop setting by apply BSF (e.g., h264_metadata) on the
>> bitstream.
>>
>>>
>>> Finally, avctx->sample_aspect_ratio should be propagated into
>> aspect-width and aspect-height. Something like this:
>>>
>>> AVRational sar = avctx->sample_aspect_ratio;
>>> if (!sar.num || !sar.den)
>>> sar.num = sar.den = 1;
>>> av_reduce(&sar.num, &sar.den, sar.num, sar.den, 4096);
>>> AMediaFormat_setInt32(format, "aspect-width", sar.num);
>>> AMediaFormat_setInt32(format, "aspect-height", sar.den);
>>>
>>
>> You mean sar-width/sar-height?
>>
>> EXPORT const char* AMEDIAFORMAT_KEY_SAR_HEIGHT = "sar-height";
>> EXPORT const char* AMEDIAFORMAT_KEY_SAR_WIDTH = "sar-width";
>>
>> They are available in NDK since API level 29 (Android 10)
>>
>> extern const char* AMEDIAFORMAT_KEY_SAR_HEIGHT __INTRODUCED_IN(29);
>> extern const char* AMEDIAFORMAT_KEY_SAR_WIDTH __INTRODUCED_IN(29);
>>
>> And they were added to Java MediaFormat since API level 30.
>>
>>
>> https://developer.android.com/reference/android/media/MediaFormat#KEY_PIXEL_ASPECT_RATIO_WIDTH
>>
>> It’s uncommon for Java API got a feature late than NDK. I will keep
>> a note and do more test before setting them.
>>
>>>
>>> +
>>> + if (avctx->pix_fmt == AV_PIX_FMT_MEDIACODEC) {
>>> + AVMediaCodecContext *user_ctx = avctx->hwaccel_context;
>>> + if (avctx->hw_device_ctx) {
>>> + AVHWDeviceContext *device_ctx =
>> (AVHWDeviceContext*)(avctx->hw_device_ctx->data);
>>> + AVMediaCodecDeviceContext *dev_ctx;
>>> +
>>> + if (device_ctx->type != AV_HWDEVICE_TYPE_MEDIACODEC ||
>> !device_ctx->hwctx) {
>>> + ret = AVERROR(EINVAL);
>>> + goto bailout;
>>> + }
>>> + dev_ctx = device_ctx->hwctx;
>>> + s->window = ff_mediacodec_surface_ref(dev_ctx->surface,
>> dev_ctx->native_window, avctx);
>>> + }
>>> +
>>> + if (!s->window && user_ctx && user_ctx->surface)
>>> + s->window = ff_mediacodec_surface_ref(user_ctx->surface,
>> NULL, avctx);
>>> +
>>> + if (!s->window) {
>>> + ret = AVERROR(EINVAL);
>>> + av_log(avctx, AV_LOG_ERROR, "Missing hw_device_ctx or
>> hwaccel_context for AV_PIX_FMT_MEDIACODEC\n");
>>> + goto bailout;
>>> + }
>>> + }
>>> +
>>> + for (int i = 0; i < FF_ARRAY_ELEMS(color_formats); i++) {
>>> + if (avctx->pix_fmt == color_formats[i].pix_fmt) {
>>> + ff_AMediaFormat_setInt32(format, "color-format",
>>> + color_formats[i].color_format);
>>> + break;
>>>
>>> do we need error/fallback if no match is found?
>>
>> The supported pix_fmts is specified
>>
>> .priv_data_size = sizeof(MediaCodecEncContext), \
>> .p.pix_fmts = avc_pix_fmts, \
>> .init = mediacodec_init, \
>>
>> It has been checked in encoder.c encode_preinit_video(), so check it again
>> is
>> optional but not necessary in my opinion.
>>
>>>
>>>
>>> + }
>>> + }
>>> +
>>> + if (avctx->bit_rate)
>>> + ff_AMediaFormat_setInt32(format, "bitrate", avctx->bit_rate);
>>> + // frame-rate and i-frame-interval are required to configure codec
>>> + if (avctx->framerate.num >= avctx->framerate.den &&
>> avctx->framerate.den > 0)
>>> + s->fps = avctx->framerate.num / avctx->framerate.den;
>>> + else
>>> + s->fps = 30;
>>> + gop = round(avctx->gop_size / s->fps);
>>> + if (gop == 0)
>>> + gop = 2;
>>>
>>> can we read gop from avctx? in other implementations i have seen gop
>> hardcoded to 1
>>
>> I think we should respect gop_size setting.
>>
>> I will add some log message and change default gop to 1 in patch v2.
>>
>>>
>>> for fps value, can we use av_q2d(avctx->framerate)
>>
>> q2d() is for double, fps is integer here.
>>
>>>
>>>
>>> + ff_AMediaFormat_setInt32(format, "frame-rate", s->fps);
>>> + ff_AMediaFormat_setInt32(format, "i-frame-interval", gop);
>>> +
>>>
>>> for H264 encoding, you can pass "profile" and "level". for example
>> profile=0x08 for High and level=0x4000 for 5.0
>>>
>>> https://stackoverflow.com/a/38999412/332798
>>
>> I’m planning to add profile/level support after the basic patch is applied.
>> There are some unresolved issue here:
>>
>> 1. I have a device which failed at configure() when profile has been set,
>> even for baseline.
>>
>
> Thanks for sharing this. Today I had the same experience,
> with OMX.rk.video_encoder.avc trying to pass profile/level.
>
> I see the following message in logcat. Did you see the same behavior?
>
> 11-20 21:55:16.132 5086 5098 W ACodec : [OMX.rk.video_encoder.avc]
> stopping checking profiles after 32: 8/1
> 11-20 21:55:16.132 5086 5098 E ACodec : [OMX.rk.video_encoder.avc]
> configureCodec returning error -1010
It’s a device with SnapDragon 845.
Success without setting profile:
I/ExtendedACodec: setupVideoEncoder()
W/OMXUtils: do not know color format 0x7fa30c06 = 2141391878
W/OMXUtils: do not know color format 0x7fa30c04 = 2141391876
W/OMXUtils: do not know color format 0x7fa30c00 = 2141391872
W/OMXUtils: do not know color format 0x7fa30c09 = 2141391881
W/OMXUtils: do not know color format 0x7fa30c0a = 2141391882
W/OMXUtils: do not know color format 0x7fa30c08 = 2141391880
W/OMXUtils: do not know color format 0x7fa30c07 = 2141391879
W/OMXUtils: do not know color format 0x7f000789 = 2130708361
I/ACodec: setupAVCEncoderParameters with [profile: High] [level: Level1]
I/ACodec: [OMX.qcom.video.encoder.avc] cannot encode HDR static metadata. Ignoring.
I/ACodec: setupVideoEncoder succeeded
Failed when pass profile (no matter which profile)
I/ExtendedACodec: setupVideoEncoder()
W/OMXUtils: do not know color format 0x7fa30c06 = 2141391878
W/OMXUtils: do not know color format 0x7fa30c04 = 2141391876
W/OMXUtils: do not know color format 0x7fa30c00 = 2141391872
W/OMXUtils: do not know color format 0x7fa30c09 = 2141391881
W/OMXUtils: do not know color format 0x7fa30c0a = 2141391882
W/OMXUtils: do not know color format 0x7fa30c08 = 2141391880
W/OMXUtils: do not know color format 0x7fa30c07 = 2141391879
W/OMXUtils: do not know color format 0x7f000789 = 2130708361
E/ExtendedACodec: [OMX.qcom.video.encoder.avc] configureCodec returning error -38
E/ACodec: signalError(omxError 0x80001001, internalError -2147483648)
E/ACodec: [OMX.qcom.video.encoder.avc] configureCodec returning error -38
E/ACodec: signalError(omxError 0x80001001, internalError -2147483648)
E/MediaCodec: Codec reported err 0x80001001, actionCode 0, while in state 3
E/MediaCodec: Codec reported err 0x80001001, actionCode 0, while in state 0
E/MediaCodec: configure failed with err 0x80001001, resetting…
The device isn’t Pixel 3. Pixel 3 has the almost the same SOC but got
no problem.
>
>
>>
>> 2. DTS is missing in MediaCodec API. For the default baseline profile,
>> there
>> is no problem. Trouble comes when we set profile to mainline or high. If
>> Surface/ANativeWindow is used, and the frames come from our MediaCodec
>> decoder
>> wrapper, we can control it’s 'render' (send to encoder's surface) via
>> av_mediacodec_release_buffer(). A DTS generation strategy works in this
>> case.
>> However, if frames comes from other sources, like a camera, there is no way
>> to control the 'render' yet, so DTS is missing in this case.
>>
>> Configure profile/level and B frames should come together.
>>
>>>
>>>
>>> +
>>> + ret = ff_AMediaCodec_getConfigureFlagEncode(s->codec);
>>> + ret = ff_AMediaCodec_configure(s->codec, format, s->window, NULL,
>> ret);
>>> + if (ret) {
>>> + av_log(avctx, AV_LOG_ERROR, "MediaCodec configure failed,
>> %s\n", av_err2str(ret));
>>> + goto bailout;
>>> + }
>>> +
>>> + ret = ff_AMediaCodec_start(s->codec);
>>> + if (ret) {
>>> + av_log(avctx, AV_LOG_ERROR, "MediaCodec failed to start, %s\n",
>> av_err2str(ret));
>>> + goto bailout;
>>> + }
>>> +
>>> + mediacodec_output_format(avctx);
>>> +
>>> + s->frame = av_frame_alloc();
>>> + if (!s->frame)
>>> + ret = AVERROR(ENOMEM);
>>> +
>>> +bailout:
>>> + if (format)
>>> + ff_AMediaFormat_delete(format);
>>> + return ret;
>>> +}
>>> +
>>> +static int mediacodec_receive(AVCodecContext *avctx,
>>> + AVPacket *pkt,
>>> + int *got_packet)
>>> +{
>>> + MediaCodecEncContext *s = avctx->priv_data;
>>> + FFAMediaCodec *codec = s->codec;
>>> + FFAMediaCodecBufferInfo out_info = {0};
>>> + uint8_t *out_buf;
>>> + size_t out_size = 0;
>>> + int ret;
>>> + int extradata_size = 0;
>>> + int64_t timeout_us = s->eof_sent ? OUTPUT_DEQUEUE_TIMEOUT_US : 0;
>>> + ssize_t index = ff_AMediaCodec_dequeueOutputBuffer(codec,
>> &out_info, timeout_us);
>>> +
>>> + if (ff_AMediaCodec_infoTryAgainLater(codec, index))
>>> + return AVERROR(EAGAIN);
>>> +
>>> + if (ff_AMediaCodec_infoOutputFormatChanged(codec, index)) {
>>> + mediacodec_output_format(avctx);
>>> + return AVERROR(EAGAIN);
>>> + }
>>> +
>>> + if (ff_AMediaCodec_infoOutputBuffersChanged(codec, index)) {
>>> + ff_AMediaCodec_cleanOutputBuffers(codec);
>>> + return AVERROR(EAGAIN);
>>> + }
>>> +
>>> + if (index < 0)
>>> + return AVERROR_EXTERNAL;
>>> +
>>> + if (out_info.flags & ff_AMediaCodec_getBufferFlagEndOfStream(codec))
>>> + return AVERROR_EOF;
>>> +
>>> + out_buf = ff_AMediaCodec_getOutputBuffer(codec, index, &out_size);
>>> + if (!out_buf) {
>>> + ret = AVERROR_EXTERNAL;
>>> + goto bailout;
>>> + }
>>> +
>>> + if (out_info.flags &
>> ff_AMediaCodec_getBufferFlagCodecConfig(codec)) {
>>> + ret = av_reallocp(&s->extradata, out_info.size);
>>> + if (ret)
>>> + goto bailout;
>>> +
>>> + s->extradata_size = out_info.size;
>>> + memcpy(s->extradata, out_buf + out_info.offset, out_info.size);
>>> + ff_AMediaCodec_releaseOutputBuffer(codec, index, false);
>>> + // try immediately
>>> + return mediacodec_receive(avctx, pkt, got_packet);
>>> + }
>>> +
>>> + ret = ff_get_encode_buffer(avctx, pkt, out_info.size +
>> s->extradata_size, 0);
>>> + if (ret < 0)
>>> + goto bailout;
>>> +
>>> + if (s->extradata_size) {
>>> + extradata_size = s->extradata_size;
>>> + s->extradata_size = 0;
>>> + memcpy(pkt->data, s->extradata, extradata_size);
>>> + }
>>> + memcpy(pkt->data + extradata_size, out_buf + out_info.offset,
>> out_info.size);
>>> + pkt->pts = av_rescale_q(out_info.presentationTimeUs,
>> AV_TIME_BASE_Q, avctx->time_base);
>>> + if (s->ts_tail != s->ts_head) {
>>> + pkt->dts = s->timestamps[s->ts_tail];
>>> + s->ts_tail = (s->ts_tail + 1) % FF_ARRAY_ELEMS(s->timestamps);
>>> + }
>>> +
>>> + if (out_info.flags & ff_AMediaCodec_getBufferFlagKeyFrame(codec))
>>> + pkt->flags |= AV_PKT_FLAG_KEY;
>>> + ret = 0;
>>> + *got_packet = 1;
>>> +
>>> + av_log(avctx, AV_LOG_TRACE, "receive packet pts %" PRId64 " dts %"
>> PRId64
>>> + " flags %d extradata %d\n",
>>> + pkt->pts, pkt->dts, pkt->flags, extradata_size);
>>> +
>>> +bailout:
>>> + ff_AMediaCodec_releaseOutputBuffer(codec, index, false);
>>> + return ret;
>>> +}
>>> +
>>> +static void copy_frame_to_buffer(AVCodecContext *avctx, const AVFrame
>> *frame, uint8_t *dst, size_t size)
>>> +{
>>> + MediaCodecEncContext *s = avctx->priv_data;
>>> + uint8_t *dst_data[4] = {};
>>> + int dst_linesize[4] = {};
>>> + const uint8_t *src_data[4] = {
>>> + frame->data[0], frame->data[1], frame->data[2],
>> frame->data[3]
>>> + };
>>> +
>>> + if (avctx->pix_fmt == AV_PIX_FMT_YUV420P) {
>>> + dst_data[0] = dst;
>>> + dst_data[1] = dst + s->width * s->height;
>>> + dst_data[2] = dst_data[1] + s->width * s->height / 4;
>>> +
>>> + dst_linesize[0] = s->width;
>>> + dst_linesize[1] = dst_linesize[2] = s->width / 2;
>>> + } else if (avctx->pix_fmt == AV_PIX_FMT_NV12) {
>>> + dst_data[0] = dst;
>>> + dst_data[1] = dst + s->width * s->height;
>>> +
>>> + dst_linesize[0] = s->width;
>>> + dst_linesize[1] = s->width;
>>> + } else {
>>> + av_assert0(0);
>>> + }
>>> +
>>> + av_image_copy(dst_data, dst_linesize, src_data, frame->linesize,
>>> + avctx->pix_fmt, avctx->width, avctx->height);
>>> +}
>>> +
>>> +static int mediacodec_send(AVCodecContext *avctx,
>>> + const AVFrame *frame) {
>>> + MediaCodecEncContext *s = avctx->priv_data;
>>> + FFAMediaCodec *codec = s->codec;
>>> + ssize_t index;
>>> + uint8_t *input_buf = NULL;
>>> + size_t input_size = 0;
>>> + int64_t pts = 0;
>>> + uint32_t flags = 0;
>>> + int64_t timeout_us;
>>> +
>>> + if (s->eof_sent)
>>> + return 0;
>>> +
>>> + if (s->window) {
>>> + if (!frame) {
>>> + s->eof_sent = 1;
>>> + return ff_AMediaCodec_signalEndOfInputStream(codec);
>>> + }
>>> +
>>> +
>>> + if (frame->data[3]) {
>>> + pts = av_rescale_q(frame->pts, avctx->time_base,
>> AV_TIME_BASE_Q);
>>> + s->timestamps[s->ts_head] = frame->pts;
>>> + s->ts_head = (s->ts_head + 1) %
>> FF_ARRAY_ELEMS(s->timestamps);
>>> +
>>> + av_mediacodec_release_buffer((AVMediaCodecBuffer
>> *)frame->data[3], 1);
>>> + }
>>> + return 0;
>>> + }
>>> +
>>> + timeout_us = INPUT_DEQUEUE_TIMEOUT_US;
>>> + index = ff_AMediaCodec_dequeueInputBuffer(codec, timeout_us);
>>> + if (ff_AMediaCodec_infoTryAgainLater(codec, index))
>>> + return AVERROR(EAGAIN);
>>> +
>>> + if (index < 0) {
>>> + av_log(avctx, AV_LOG_ERROR, "dequeue input buffer failed, %zd",
>> index);
>>> + return AVERROR_EXTERNAL;
>>> + }
>>> +
>>> + if (frame) {
>>> + input_buf = ff_AMediaCodec_getInputBuffer(codec, index,
>> &input_size);
>>> + copy_frame_to_buffer(avctx, frame, input_buf, input_size);
>>> +
>>> + pts = av_rescale_q(frame->pts, avctx->time_base,
>> AV_TIME_BASE_Q);
>>> +
>>> + s->timestamps[s->ts_head] = frame->pts;
>>> + s->ts_head = (s->ts_head + 1) % FF_ARRAY_ELEMS(s->timestamps);
>>> + } else {
>>> + flags |= ff_AMediaCodec_getBufferFlagEndOfStream(codec);
>>> + s->eof_sent = 1;
>>> + }
>>> +
>>>
>>> it would be nice to propagate keyframes here (frame->pict_type ==
>> AV_PICTURE_TYPE_I). it is only possible on API26 with
>> AMediaCodec_setParameters and PARAMETER_KEY_REQUEST_SYNC_FRAME
>>
>> It’s a nice feature. I’m planning to add support after the basic function
>> is working.
>>
>>>
>>>
>>> + ff_AMediaCodec_queueInputBuffer(codec, index, 0, input_size, pts,
>> flags);
>>> + return 0;
>>> +}
>>> +
>>> +static int mediacodec_encode(AVCodecContext *avctx, AVPacket *pkt)
>>> +{
>>> + MediaCodecEncContext *s = avctx->priv_data;
>>> + int ret;
>>> + int got_packet = 0;
>>> +
>>> + // Return on three case:
>>> + // 1. Serious error
>>> + // 2. Got a packet success
>>> + // 3. No AVFrame is available yet (don't return if get_frame return
>> EOF)
>>> + while (1) {
>>> + ret = mediacodec_receive(avctx, pkt, &got_packet);
>>> + if (!ret)
>>> + return 0;
>>> + else if (ret != AVERROR(EAGAIN))
>>> + return ret;
>>> +
>>> + if (!s->frame->buf[0]) {
>>> + ret = ff_encode_get_frame(avctx, s->frame);
>>> + if (ret && ret != AVERROR_EOF)
>>> + return ret;
>>> + }
>>> +
>>> + ret = mediacodec_send(avctx, s->frame->buf[0] ? s->frame :
>> NULL);
>>> + if (!ret)
>>> + av_frame_unref(s->frame);
>>> + else if (ret != AVERROR(EAGAIN))
>>> + return ret;
>>> + }
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static av_cold int mediacodec_close(AVCodecContext *avctx)
>>> +{
>>> + MediaCodecEncContext *s = avctx->priv_data;
>>> + if (s->codec) {
>>> + ff_AMediaCodec_stop(s->codec);
>>> + ff_AMediaCodec_delete(s->codec);
>>> + s->codec = NULL;
>>> + }
>>> +
>>> + if (s->window) {
>>> + ff_mediacodec_surface_unref(s->window, avctx);
>>> + s->window = NULL;
>>> + }
>>> +
>>> + av_frame_free(&s->frame);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static const AVCodecHWConfigInternal *const mediacodec_hw_configs[] = {
>>> + &(const AVCodecHWConfigInternal) {
>>> + .public = {
>>> + .pix_fmt = AV_PIX_FMT_MEDIACODEC,
>>> + .methods = AV_CODEC_HW_CONFIG_METHOD_AD_HOC |
>>> + AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX,
>>> + .device_type = AV_HWDEVICE_TYPE_MEDIACODEC,
>>> + },
>>> + .hwaccel = NULL,
>>> + },
>>> + NULL
>>> +};
>>> +
>>> +#define OFFSET(x) offsetof(MediaCodecEncContext, x)
>>> +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
>>> +static const AVOption common_options[] = {
>>> + { "ndk_codec", "Use MediaCodec from NDK",
>>> + OFFSET(use_ndk_codec), AV_OPT_TYPE_BOOL, {.i64 =
>> -1}, -1, 1, VE },
>>> + { NULL },
>>> +};
>>> +
>>> +#define MEDIACODEC_ENCODER_CLASS(name) \
>>> +static const AVClass name ## _mediacodec_class = { \
>>> + .class_name = #name "_mediacodec", \
>>> + .item_name = av_default_item_name, \
>>> + .option = common_options, \
>>> + .version = LIBAVUTIL_VERSION_INT, \
>>> +}; \
>>> +
>>> +#define DECLARE_MEDIACODEC_ENCODER(short_name, long_name, codec_id)
>> \
>>> +MEDIACODEC_ENCODER_CLASS(short_name)
>> \
>>> +const FFCodec ff_ ## short_name ## _mediacodec_encoder = {
>> \
>>> + .p.name = #short_name "_mediacodec",
>> \
>>> + CODEC_LONG_NAME(long_name " Android MediaCodec encoder"),
>> \
>>> + .p.type = AVMEDIA_TYPE_VIDEO,
>> \
>>> + .p.id = codec_id,
>> \
>>> + .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,
>> \
>>> + .p.priv_class = &short_name ## _mediacodec_class,
>> \
>>> + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
>> \
>>> + .p.wrapper_name = "mediacodec",
>> \
>>> + .hw_configs = mediacodec_hw_configs,
>> \
>>> +};
>> \
>>> +
>>> +#if CONFIG_H264_MEDIACODEC_ENCODER
>>> +DECLARE_MEDIACODEC_ENCODER(h264, "H.264", AV_CODEC_ID_H264)
>>> +#endif
>>> +
>>> +#if CONFIG_HEVC_MEDIACODEC_ENCODER
>>> +DECLARE_MEDIACODEC_ENCODER(hevc, "H.265", AV_CODEC_ID_HEVC)
>>> +#endif
>>> diff --git a/libavcodec/version.h b/libavcodec/version.h
>>> index 43d0d9a9fc..86ac0f3871 100644
>>> --- a/libavcodec/version.h
>>> +++ b/libavcodec/version.h
>>> @@ -29,8 +29,8 @@
>>>
>>> #include "version_major.h"
>>>
>>> -#define LIBAVCODEC_VERSION_MINOR 51
>>> -#define LIBAVCODEC_VERSION_MICRO 101
>>> +#define LIBAVCODEC_VERSION_MINOR 52
>>> +#define LIBAVCODEC_VERSION_MICRO 100
>>>
>>> #define LIBAVCODEC_VERSION_INT
>> AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
>>>
>> LIBAVCODEC_VERSION_MINOR, \
>>> --
>>> 2.25.1
>>>
>>
>>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request at ffmpeg.org with subject "unsubscribe".
More information about the ffmpeg-devel
mailing list