[FFmpeg-cvslog] avcodec: add Mediacodec audio decoders support
Matthieu Bouron
git at videolan.org
Sun Sep 1 13:26:17 EEST 2024
ffmpeg | branch: master | Matthieu Bouron <matthieu.bouron at gmail.com> | Wed Jun 12 15:42:10 2024 +0200| [0a780d3076fe44fe6d641e84e291b567fca29999] | committer: Matthieu Bouron
avcodec: add Mediacodec audio decoders support
Signed-off-by: Matthieu Bouron <matthieu.bouron at gmail.com>
> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=0a780d3076fe44fe6d641e84e291b567fca29999
---
Changelog | 1 +
configure | 8 +
libavcodec/Makefile | 4 +
libavcodec/allcodecs.c | 4 +
libavcodec/mediacodecdec.c | 102 +++++++++++-
libavcodec/mediacodecdec_common.c | 333 ++++++++++++++++++++++++++++++++++----
6 files changed, 421 insertions(+), 31 deletions(-)
diff --git a/Changelog b/Changelog
index 571b27ad98..583de26f1b 100644
--- a/Changelog
+++ b/Changelog
@@ -18,6 +18,7 @@ version <next>:
- D3D12VA HEVC encoder
- Cropping metadata parsing and writing in Matroska and MP4/MOV de/muxers
- Intel QSV-accelerated VVC decoding
+- MediaCodec AAC/AMR-NB/AMR-WB/MP3 decoding
version 7.0:
diff --git a/configure b/configure
index 63f0429b02..44cfaebf21 100755
--- a/configure
+++ b/configure
@@ -3324,8 +3324,14 @@ amf_deps_any="libdl LoadLibrary"
nvenc_deps="ffnvcodec"
nvenc_deps_any="libdl LoadLibrary"
+aac_mediacodec_decoder_deps="mediacodec"
+aac_mediacodec_decoder_select="aac_adtstoasc_bsf aac_parser"
aac_mf_encoder_deps="mediafoundation"
ac3_mf_encoder_deps="mediafoundation"
+amrnb_mediacodec_decoder_deps="mediacodec"
+amrnb_mediacodec_decoder_select="amr_parser"
+amrwb_mediacodec_decoder_deps="mediacodec"
+amrwb_mediacodec_decoder_select="amr_parser"
av1_amf_encoder_deps="amf"
av1_cuvid_decoder_deps="cuvid CUVIDAV1PICPARAMS"
av1_mediacodec_decoder_deps="mediacodec"
@@ -3387,6 +3393,8 @@ mjpeg_qsv_encoder_select="qsvenc"
mjpeg_vaapi_encoder_deps="VAEncPictureParameterBufferJPEG"
mjpeg_vaapi_encoder_select="cbs_jpeg jpegtables vaapi_encode"
mp3_mf_encoder_deps="mediafoundation"
+mp3_mediacodec_decoder_deps="mediacodec"
+mp3_mediacodec_decoder_select="mpegaudioheader"
mpeg1_cuvid_decoder_deps="cuvid"
mpeg1_v4l2m2m_decoder_deps="v4l2_m2m mpeg1_v4l2_m2m"
mpeg2_cuvid_decoder_deps="cuvid"
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 3b4b8681f5..c60c31b270 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -197,6 +197,7 @@ OBJS-$(CONFIG_AAC_ENCODER) += aacenc.o aaccoder.o aacenctab.o \
aacenc_pred.o \
psymodel.o kbdwin.o \
mpeg4audio_sample_rates.o
+OBJS-$(CONFIG_AAC_MEDIACODEC_DECODER) += mediacodecdec.o
OBJS-$(CONFIG_AAC_MF_ENCODER) += mfenc.o mf_utils.o
OBJS-$(CONFIG_AASC_DECODER) += aasc.o msrledec.o
OBJS-$(CONFIG_AC3_DECODER) += ac3dec_float.o ac3dec_data.o ac3.o \
@@ -223,6 +224,8 @@ OBJS-$(CONFIG_AMRWB_DECODER) += amrwbdec.o celp_filters.o \
celp_math.o acelp_filters.o \
acelp_vectors.o \
acelp_pitch_delay.o
+OBJS-$(CONFIG_AMRNB_MEDIACODEC_DECODER) += mediacodecdec.o
+OBJS-$(CONFIG_AMRWB_MEDIACODEC_DECODER) += mediacodecdec.o
OBJS-$(CONFIG_AMV_ENCODER) += mjpegenc.o mjpegenc_common.o
OBJS-$(CONFIG_ANM_DECODER) += anm.o
OBJS-$(CONFIG_ANULL_DECODER) += null.o
@@ -521,6 +524,7 @@ OBJS-$(CONFIG_MP2FIXED_ENCODER) += mpegaudioenc_fixed.o mpegaudio.o \
mpegaudiotabs.o
OBJS-$(CONFIG_MP2FLOAT_DECODER) += mpegaudiodec_float.o
OBJS-$(CONFIG_MP3_DECODER) += mpegaudiodec_fixed.o
+OBJS-$(CONFIG_MP3_MEDIACODEC_DECODER) += mediacodecdec.o
OBJS-$(CONFIG_MP3_MF_ENCODER) += mfenc.o mf_utils.o
OBJS-$(CONFIG_MP3ADU_DECODER) += mpegaudiodec_fixed.o
OBJS-$(CONFIG_MP3ADUFLOAT_DECODER) += mpegaudiodec_float.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 09385be4ee..563afde355 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -822,8 +822,11 @@ extern const FFCodec ff_idf_decoder;
/* external libraries, that shouldn't be used by default if one of the
* above is available */
+extern const FFCodec ff_aac_mediacodec_decoder;
extern const FFCodec ff_aac_mf_encoder;
extern const FFCodec ff_ac3_mf_encoder;
+extern const FFCodec ff_amrnb_mediacodec_decoder;
+extern const FFCodec ff_amrwb_mediacodec_decoder;
extern const FFCodec ff_h263_v4l2m2m_encoder;
extern const FFCodec ff_libaom_av1_decoder;
/* hwaccel hooks only, so prefer external decoders */
@@ -863,6 +866,7 @@ extern const FFCodec ff_mjpeg_cuvid_decoder;
extern const FFCodec ff_mjpeg_qsv_encoder;
extern const FFCodec ff_mjpeg_qsv_decoder;
extern const FFCodec ff_mjpeg_vaapi_encoder;
+extern const FFCodec ff_mp3_mediacodec_decoder;
extern const FFCodec ff_mp3_mf_encoder;
extern const FFCodec ff_mpeg1_cuvid_decoder;
extern const FFCodec ff_mpeg2_cuvid_decoder;
diff --git a/libavcodec/mediacodecdec.c b/libavcodec/mediacodecdec.c
index 0da5fe6729..cc55b306bd 100644
--- a/libavcodec/mediacodecdec.c
+++ b/libavcodec/mediacodecdec.c
@@ -291,7 +291,11 @@ done:
CONFIG_MPEG4_MEDIACODEC_DECODER || \
CONFIG_VP8_MEDIACODEC_DECODER || \
CONFIG_VP9_MEDIACODEC_DECODER || \
- CONFIG_AV1_MEDIACODEC_DECODER
+ CONFIG_AV1_MEDIACODEC_DECODER || \
+ CONFIG_AAC_MEDIACODEC_DECODER || \
+ CONFIG_AMRNB_MEDIACODEC_DECODER || \
+ CONFIG_AMRWB_MEDIACODEC_DECODER || \
+ CONFIG_MP3_MEDIACODEC_DECODER
static int common_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format)
{
int ret = 0;
@@ -388,13 +392,55 @@ static av_cold int mediacodec_decode_init(AVCodecContext *avctx)
goto done;
break;
#endif
+#if CONFIG_AAC_MEDIACODEC_DECODER
+ case AV_CODEC_ID_AAC:
+ codec_mime = "audio/mp4a-latm";
+
+ ret = common_set_extradata(avctx, format);
+ if (ret < 0)
+ goto done;
+ break;
+#endif
+#if CONFIG_AMRNB_MEDIACODEC_DECODER
+ case AV_CODEC_ID_AMR_NB:
+ codec_mime = "audio/3gpp";
+
+ ret = common_set_extradata(avctx, format);
+ if (ret < 0)
+ goto done;
+ break;
+#endif
+#if CONFIG_AMRWB_MEDIACODEC_DECODER
+ case AV_CODEC_ID_AMR_WB:
+ codec_mime = "audio/amr-wb";
+
+ ret = common_set_extradata(avctx, format);
+ if (ret < 0)
+ goto done;
+ break;
+#endif
+#if CONFIG_MP3_MEDIACODEC_DECODER
+ case AV_CODEC_ID_MP3:
+ codec_mime = "audio/mpeg";
+
+ ret = common_set_extradata(avctx, format);
+ if (ret < 0)
+ goto done;
+ break;
+#endif
default:
av_assert0(0);
}
ff_AMediaFormat_setString(format, "mime", codec_mime);
- ff_AMediaFormat_setInt32(format, "width", avctx->width);
- ff_AMediaFormat_setInt32(format, "height", avctx->height);
+
+ if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
+ ff_AMediaFormat_setInt32(format, "width", avctx->width);
+ ff_AMediaFormat_setInt32(format, "height", avctx->height);
+ } else {
+ ff_AMediaFormat_setInt32(format, "channel-count", avctx->ch_layout.nb_channels);
+ ff_AMediaFormat_setInt32(format, "sample-rate", avctx->sample_rate);
+ }
s->ctx = av_mallocz(sizeof(*s->ctx));
if (!s->ctx) {
@@ -611,3 +657,53 @@ DECLARE_MEDIACODEC_VDEC(vp9, "VP9", AV_CODEC_ID_VP9, NULL)
#if CONFIG_AV1_MEDIACODEC_DECODER
DECLARE_MEDIACODEC_VDEC(av1, "AV1", AV_CODEC_ID_AV1, NULL)
#endif
+
+#define AD AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM
+static const AVOption ff_mediacodec_adec_options[] = {
+ { "ndk_codec", "Use MediaCodec from NDK",
+ OFFSET(use_ndk_codec), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AD },
+ { NULL }
+};
+
+#define DECLARE_MEDIACODEC_ACLASS(short_name) \
+static const AVClass ff_##short_name##_mediacodec_dec_class = { \
+ .class_name = #short_name "_mediacodec", \
+ .item_name = av_default_item_name, \
+ .option = ff_mediacodec_adec_options, \
+ .version = LIBAVUTIL_VERSION_INT, \
+};
+
+#define DECLARE_MEDIACODEC_ADEC(short_name, full_name, codec_id, bsf) \
+DECLARE_MEDIACODEC_VCLASS(short_name) \
+const FFCodec ff_ ## short_name ## _mediacodec_decoder = { \
+ .p.name = #short_name "_mediacodec", \
+ CODEC_LONG_NAME(full_name " Android MediaCodec decoder"), \
+ .p.type = AVMEDIA_TYPE_AUDIO, \
+ .p.id = codec_id, \
+ .p.priv_class = &ff_##short_name##_mediacodec_dec_class, \
+ .priv_data_size = sizeof(MediaCodecH264DecContext), \
+ .init = mediacodec_decode_init, \
+ FF_CODEC_RECEIVE_FRAME_CB(mediacodec_receive_frame), \
+ .flush = mediacodec_decode_flush, \
+ .close = mediacodec_decode_close, \
+ .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, \
+ .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, \
+ .bsfs = bsf, \
+ .p.wrapper_name = "mediacodec", \
+}; \
+
+#if CONFIG_AAC_MEDIACODEC_DECODER
+DECLARE_MEDIACODEC_ADEC(aac, "AAC", AV_CODEC_ID_AAC, "aac_adtstoasc")
+#endif
+
+#if CONFIG_AMRNB_MEDIACODEC_DECODER
+DECLARE_MEDIACODEC_ADEC(amrnb, "AMR-NB", AV_CODEC_ID_AMR_NB, NULL)
+#endif
+
+#if CONFIG_AMRWB_MEDIACODEC_DECODER
+DECLARE_MEDIACODEC_ADEC(amrwb, "AMR-WB", AV_CODEC_ID_AMR_WB, NULL)
+#endif
+
+#if CONFIG_MP3_MEDIACODEC_DECODER
+DECLARE_MEDIACODEC_ADEC(mp3, "MP3", AV_CODEC_ID_MP3, NULL)
+#endif
diff --git a/libavcodec/mediacodecdec_common.c b/libavcodec/mediacodecdec_common.c
index c888dea8cf..b1ee8b609a 100644
--- a/libavcodec/mediacodecdec_common.c
+++ b/libavcodec/mediacodecdec_common.c
@@ -23,6 +23,7 @@
#include <string.h>
#include <sys/types.h>
+#include "libavutil/avassert.h"
#include "libavutil/common.h"
#include "libavutil/hwcontext_mediacodec.h"
#include "libavutil/mem.h"
@@ -30,6 +31,7 @@
#include "libavutil/pixfmt.h"
#include "libavutil/time.h"
#include "libavutil/timestamp.h"
+#include "libavutil/channel_layout.h"
#include "avcodec.h"
#include "decode.h"
@@ -85,6 +87,107 @@
#define OUTPUT_DEQUEUE_TIMEOUT_US 8000
#define OUTPUT_DEQUEUE_BLOCK_TIMEOUT_US 1000000
+enum {
+ ENCODING_PCM_16BIT = 0x00000002,
+ ENCODING_PCM_8BIT = 0x00000003,
+ ENCODING_PCM_FLOAT = 0x00000004,
+ ENCODING_PCM_24BIT_PACKED = 0x00000015,
+ ENCODING_PCM_32BIT = 0x00000016,
+};
+
+static const struct {
+
+ int pcm_format;
+ enum AVSampleFormat sample_format;
+
+} sample_formats[] = {
+
+ { ENCODING_PCM_16BIT, AV_SAMPLE_FMT_S16 },
+ { ENCODING_PCM_8BIT, AV_SAMPLE_FMT_U8 },
+ { ENCODING_PCM_FLOAT, AV_SAMPLE_FMT_FLT },
+ { ENCODING_PCM_32BIT, AV_SAMPLE_FMT_S32 },
+ { 0 }
+};
+
+static enum AVSampleFormat mcdec_map_pcm_format(AVCodecContext *avctx,
+ MediaCodecDecContext *s,
+ int pcm_format)
+{
+ enum AVSampleFormat ret = AV_SAMPLE_FMT_NONE;
+
+ for (int i = 0; i < FF_ARRAY_ELEMS(sample_formats); i++) {
+ if (sample_formats[i].pcm_format == pcm_format) {
+ return sample_formats[i].sample_format;
+ }
+ }
+
+ av_log(avctx, AV_LOG_ERROR, "Output sample format 0x%x (value=%d) is not supported\n",
+ pcm_format, pcm_format);
+
+ return ret;
+}
+
+enum
+{
+ CHANNEL_OUT_FRONT_LEFT = 0x4,
+ CHANNEL_OUT_FRONT_RIGHT = 0x8,
+ CHANNEL_OUT_FRONT_CENTER = 0x10,
+ CHANNEL_OUT_LOW_FREQUENCY = 0x20,
+ CHANNEL_OUT_BACK_LEFT = 0x40,
+ CHANNEL_OUT_BACK_RIGHT = 0x80,
+ CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x100,
+ CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x200,
+ CHANNEL_OUT_BACK_CENTER = 0x400,
+ CHANNEL_OUT_SIDE_LEFT = 0x800,
+ CHANNEL_OUT_SIDE_RIGHT = 0x1000,
+ CHANNEL_OUT_TOP_CENTER = 0x2000,
+ CHANNEL_OUT_TOP_FRONT_LEFT = 0x4000,
+ CHANNEL_OUT_TOP_FRONT_CENTER = 0x8000,
+ CHANNEL_OUT_TOP_FRONT_RIGHT = 0x10000,
+ CHANNEL_OUT_TOP_BACK_LEFT = 0x20000,
+ CHANNEL_OUT_TOP_BACK_CENTER = 0x40000,
+ CHANNEL_OUT_TOP_BACK_RIGHT = 0x80000,
+};
+
+static const struct {
+
+ int mask;
+ uint64_t layout;
+
+} channel_masks[] = {
+ { CHANNEL_OUT_FRONT_LEFT, AV_CH_FRONT_LEFT },
+ { CHANNEL_OUT_FRONT_RIGHT, AV_CH_FRONT_RIGHT },
+ { CHANNEL_OUT_FRONT_CENTER, AV_CH_FRONT_CENTER },
+ { CHANNEL_OUT_LOW_FREQUENCY, AV_CH_LOW_FREQUENCY },
+ { CHANNEL_OUT_BACK_LEFT, AV_CH_BACK_LEFT },
+ { CHANNEL_OUT_BACK_RIGHT, AV_CH_BACK_RIGHT },
+ { CHANNEL_OUT_FRONT_LEFT_OF_CENTER, AV_CH_FRONT_LEFT_OF_CENTER },
+ { CHANNEL_OUT_FRONT_RIGHT_OF_CENTER, AV_CH_FRONT_RIGHT_OF_CENTER },
+ { CHANNEL_OUT_BACK_CENTER, AV_CH_BACK_CENTER },
+ { CHANNEL_OUT_SIDE_LEFT, AV_CH_SIDE_LEFT },
+ { CHANNEL_OUT_SIDE_RIGHT, AV_CH_SIDE_RIGHT },
+ { CHANNEL_OUT_TOP_CENTER, AV_CH_TOP_CENTER },
+ { CHANNEL_OUT_TOP_FRONT_LEFT, AV_CH_TOP_FRONT_LEFT },
+ { CHANNEL_OUT_TOP_FRONT_CENTER, AV_CH_TOP_FRONT_CENTER },
+ { CHANNEL_OUT_TOP_FRONT_RIGHT, AV_CH_TOP_FRONT_RIGHT },
+ { CHANNEL_OUT_TOP_BACK_LEFT, AV_CH_TOP_BACK_LEFT },
+ { CHANNEL_OUT_TOP_BACK_CENTER, AV_CH_TOP_BACK_CENTER },
+ { CHANNEL_OUT_TOP_BACK_RIGHT, AV_CH_TOP_BACK_RIGHT },
+};
+
+static uint64_t mcdec_map_channel_mask(AVCodecContext *avctx,
+ int channel_mask)
+{
+ uint64_t channel_layout = 0;
+
+ for (int i = 0; i < FF_ARRAY_ELEMS(channel_masks); i++) {
+ if (channel_mask & channel_masks[i].mask)
+ channel_layout |= channel_masks[i].layout;
+ }
+
+ return channel_layout;
+}
+
enum {
COLOR_FormatYUV420Planar = 0x13,
COLOR_FormatYUV420SemiPlanar = 0x15,
@@ -265,13 +368,79 @@ fail:
return ret;
}
-static int mediacodec_wrap_sw_buffer(AVCodecContext *avctx,
- MediaCodecDecContext *s,
- uint8_t *data,
- size_t size,
- ssize_t index,
- FFAMediaCodecBufferInfo *info,
- AVFrame *frame)
+static int mediacodec_wrap_sw_audio_buffer(AVCodecContext *avctx,
+ MediaCodecDecContext *s,
+ uint8_t *data,
+ size_t size,
+ ssize_t index,
+ FFAMediaCodecBufferInfo *info,
+ AVFrame *frame)
+{
+ int ret = 0;
+ int status = 0;
+ const int sample_size = av_get_bytes_per_sample(avctx->sample_fmt);
+ if (!sample_size) {
+ av_log(avctx, AV_LOG_ERROR, "Could not get bytes per sample\n");
+ ret = AVERROR(ENOSYS);
+ goto done;
+ }
+
+ frame->format = avctx->sample_fmt;
+ frame->sample_rate = avctx->sample_rate;
+ frame->nb_samples = info->size / (sample_size * avctx->ch_layout.nb_channels);
+
+ ret = av_channel_layout_copy(&frame->ch_layout, &avctx->ch_layout);
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Could not copy channel layout\n");
+ goto done;
+ }
+
+ /* MediaCodec buffers needs to be copied to our own refcounted buffers
+ * because the flush command invalidates all input and output buffers.
+ */
+ ret = ff_get_buffer(avctx, frame, 0);
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Could not allocate buffer\n");
+ goto done;
+ }
+
+ /* Override frame->pts as ff_get_buffer will override its value based
+ * on the last avpacket received which is not in sync with the frame:
+ * * N avpackets can be pushed before 1 frame is actually returned
+ * * 0-sized avpackets are pushed to flush remaining frames at EOS */
+ if (avctx->pkt_timebase.num && avctx->pkt_timebase.den) {
+ frame->pts = av_rescale_q(info->presentationTimeUs,
+ AV_TIME_BASE_Q,
+ avctx->pkt_timebase);
+ } else {
+ frame->pts = info->presentationTimeUs;
+ }
+ frame->pkt_dts = AV_NOPTS_VALUE;
+
+ av_log(avctx, AV_LOG_TRACE,
+ "Frame: format=%d channels=%d sample_rate=%d nb_samples=%d",
+ avctx->sample_fmt, avctx->ch_layout.nb_channels, avctx->sample_rate, frame->nb_samples);
+
+ memcpy(frame->data[0], data, info->size);
+
+ ret = 0;
+done:
+ status = ff_AMediaCodec_releaseOutputBuffer(s->codec, index, 0);
+ if (status < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to release output buffer\n");
+ ret = AVERROR_EXTERNAL;
+ }
+
+ return ret;
+}
+
+static int mediacodec_wrap_sw_video_buffer(AVCodecContext *avctx,
+ MediaCodecDecContext *s,
+ uint8_t *data,
+ size_t size,
+ ssize_t index,
+ FFAMediaCodecBufferInfo *info,
+ AVFrame *frame)
{
int ret = 0;
int status = 0;
@@ -343,6 +512,22 @@ done:
return ret;
}
+static int mediacodec_wrap_sw_buffer(AVCodecContext *avctx,
+ MediaCodecDecContext *s,
+ uint8_t *data,
+ size_t size,
+ ssize_t index,
+ FFAMediaCodecBufferInfo *info,
+ AVFrame *frame)
+{
+ if (avctx->codec_type == AVMEDIA_TYPE_AUDIO)
+ return mediacodec_wrap_sw_audio_buffer(avctx, s, data, size, index, info, frame);
+ else if (avctx->codec_type == AVMEDIA_TYPE_VIDEO)
+ return mediacodec_wrap_sw_video_buffer(avctx, s, data, size, index, info, frame);
+ else
+ av_assert0(0);
+}
+
#define AMEDIAFORMAT_GET_INT32(name, key, mandatory) do { \
int32_t value = 0; \
if (ff_AMediaFormat_getInt32(s->format, key, &value)) { \
@@ -354,7 +539,7 @@ done:
} \
} while (0) \
-static int mediacodec_dec_parse_format(AVCodecContext *avctx, MediaCodecDecContext *s)
+static int mediacodec_dec_parse_video_format(AVCodecContext *avctx, MediaCodecDecContext *s)
{
int ret = 0;
int width = 0;
@@ -463,6 +648,63 @@ fail:
return ret;
}
+static int mediacodec_dec_parse_audio_format(AVCodecContext *avctx, MediaCodecDecContext *s)
+{
+ int ret = 0;
+ int sample_rate = 0;
+ int channel_count = 0;
+ int channel_mask = 0;
+ int pcm_encoding = 0;
+ char *format = NULL;
+
+ if (!s->format) {
+ av_log(avctx, AV_LOG_ERROR, "Output MediaFormat is not set\n");
+ return AVERROR(EINVAL);
+ }
+
+ format = ff_AMediaFormat_toString(s->format);
+ if (!format) {
+ return AVERROR_EXTERNAL;
+ }
+ av_log(avctx, AV_LOG_DEBUG, "Parsing MediaFormat %s\n", format);
+
+ /* Mandatory fields */
+ AMEDIAFORMAT_GET_INT32(channel_count, "channel-count", 1);
+ AMEDIAFORMAT_GET_INT32(sample_rate, "sample-rate", 1);
+
+ AMEDIAFORMAT_GET_INT32(pcm_encoding, "pcm-encoding", 0);
+ if (pcm_encoding)
+ avctx->sample_fmt = mcdec_map_pcm_format(avctx, s, pcm_encoding);
+ else
+ avctx->sample_fmt = AV_SAMPLE_FMT_S16;
+
+ avctx->sample_rate = sample_rate;
+
+ AMEDIAFORMAT_GET_INT32(channel_mask, "channel-mask", 0);
+ if (channel_mask)
+ av_channel_layout_from_mask(&avctx->ch_layout, mcdec_map_channel_mask(avctx, channel_mask));
+ else
+ av_channel_layout_default(&avctx->ch_layout, channel_count);
+
+ av_log(avctx, AV_LOG_INFO,
+ "Output parameters channel-count=%d channel-layout=%x sample-rate=%d\n",
+ channel_count, channel_mask, sample_rate);
+
+fail:
+ av_freep(&format);
+ return ret;
+}
+
+static int mediacodec_dec_parse_format(AVCodecContext *avctx, MediaCodecDecContext *s)
+{
+ if (avctx->codec_type == AVMEDIA_TYPE_AUDIO)
+ return mediacodec_dec_parse_audio_format(avctx, s);
+ else if (avctx->codec_type == AVMEDIA_TYPE_VIDEO)
+ return mediacodec_dec_parse_video_format(avctx, s);
+ else
+ av_assert0(0);
+}
+
static int mediacodec_dec_flush_codec(AVCodecContext *avctx, MediaCodecDecContext *s)
{
FFAMediaCodec *codec = s->codec;
@@ -486,11 +728,9 @@ static int mediacodec_dec_flush_codec(AVCodecContext *avctx, MediaCodecDecContex
return 0;
}
-int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s,
- const char *mime, FFAMediaFormat *format)
+static int mediacodec_dec_get_video_codec(AVCodecContext *avctx, MediaCodecDecContext *s,
+ const char *mime, FFAMediaFormat *format)
{
- int ret = 0;
- int status;
int profile;
enum AVPixelFormat pix_fmt;
@@ -499,12 +739,6 @@ int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s,
AV_PIX_FMT_NONE,
};
- s->avctx = avctx;
- atomic_init(&s->refcount, 1);
- atomic_init(&s->hw_buffer_count, 0);
- atomic_init(&s->serial, 1);
- s->current_input_buffer = -1;
-
pix_fmt = ff_get_format(avctx, pix_fmts);
if (pix_fmt == AV_PIX_FMT_MEDIACODEC) {
AVMediaCodecContext *user_ctx = avctx->hwaccel_context;
@@ -536,8 +770,7 @@ int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s,
// getCodecNameByType() can fail due to missing JVM, while NDK
// mediacodec can be used without JVM.
if (!s->use_ndk_codec) {
- ret = AVERROR_EXTERNAL;
- goto fail;
+ return AVERROR_EXTERNAL;
}
av_log(avctx, AV_LOG_INFO, "Failed to getCodecNameByType\n");
} else {
@@ -556,10 +789,52 @@ int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s,
}
if (!s->codec) {
av_log(avctx, AV_LOG_ERROR, "Failed to create media decoder for type %s and name %s\n", mime, s->codec_name);
- ret = AVERROR_EXTERNAL;
- goto fail;
+ return AVERROR_EXTERNAL;
+ }
+
+ return 0;
+}
+
+static int mediacodec_dec_get_audio_codec(AVCodecContext *avctx, MediaCodecDecContext *s,
+ const char *mime, FFAMediaFormat *format)
+{
+ s->codec = ff_AMediaCodec_createDecoderByType(mime, s->use_ndk_codec);
+ if (!s->codec) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to create media decoder for mime %s\n", mime);
+ return AVERROR_EXTERNAL;
+ }
+
+ s->codec_name = ff_AMediaCodec_getName(s->codec);
+ if (!s->codec_name) {
+ s->codec_name = av_strdup(mime);
+ if (!s->codec_name)
+ return AVERROR(ENOMEM);
}
+ return 0;
+}
+
+int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s,
+ const char *mime, FFAMediaFormat *format)
+{
+ int ret;
+ int status;
+
+ s->avctx = avctx;
+ atomic_init(&s->refcount, 1);
+ atomic_init(&s->hw_buffer_count, 0);
+ atomic_init(&s->serial, 1);
+ s->current_input_buffer = -1;
+
+ if (avctx->codec_type == AVMEDIA_TYPE_AUDIO)
+ ret = mediacodec_dec_get_audio_codec(avctx, s, mime, format);
+ else if (avctx->codec_type == AVMEDIA_TYPE_VIDEO)
+ ret = mediacodec_dec_get_video_codec(avctx, s, mime, format);
+ else
+ av_assert0(0);
+ if (ret < 0)
+ goto fail;
+
status = ff_AMediaCodec_configure(s->codec, format, s->surface, NULL, 0);
if (status < 0) {
char *desc = ff_AMediaFormat_toString(format);
@@ -583,12 +858,14 @@ int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s,
goto fail;
}
- s->format = ff_AMediaCodec_getOutputFormat(s->codec);
- if (s->format) {
- if ((ret = mediacodec_dec_parse_format(avctx, s)) < 0) {
- av_log(avctx, AV_LOG_ERROR,
- "Failed to configure context\n");
- goto fail;
+ if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
+ s->format = ff_AMediaCodec_getOutputFormat(s->codec);
+ if (s->format) {
+ if ((ret = mediacodec_dec_parse_format(avctx, s)) < 0) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Failed to configure context\n");
+ goto fail;
+ }
}
}
More information about the ffmpeg-cvslog
mailing list