1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2024-11-21 10:55:51 +02:00

avcodec: add Mediacodec audio decoders support

Signed-off-by: Matthieu Bouron <matthieu.bouron@gmail.com>
This commit is contained in:
Matthieu Bouron 2024-06-12 15:42:10 +02:00
parent 7d1dda4892
commit 0a780d3076
6 changed files with 421 additions and 31 deletions

View File

@ -18,6 +18,7 @@ version <next>:
- D3D12VA HEVC encoder - D3D12VA HEVC encoder
- Cropping metadata parsing and writing in Matroska and MP4/MOV de/muxers - Cropping metadata parsing and writing in Matroska and MP4/MOV de/muxers
- Intel QSV-accelerated VVC decoding - Intel QSV-accelerated VVC decoding
- MediaCodec AAC/AMR-NB/AMR-WB/MP3 decoding
version 7.0: version 7.0:

8
configure vendored
View File

@ -3324,8 +3324,14 @@ amf_deps_any="libdl LoadLibrary"
nvenc_deps="ffnvcodec" nvenc_deps="ffnvcodec"
nvenc_deps_any="libdl LoadLibrary" nvenc_deps_any="libdl LoadLibrary"
aac_mediacodec_decoder_deps="mediacodec"
aac_mediacodec_decoder_select="aac_adtstoasc_bsf aac_parser"
aac_mf_encoder_deps="mediafoundation" aac_mf_encoder_deps="mediafoundation"
ac3_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_amf_encoder_deps="amf"
av1_cuvid_decoder_deps="cuvid CUVIDAV1PICPARAMS" av1_cuvid_decoder_deps="cuvid CUVIDAV1PICPARAMS"
av1_mediacodec_decoder_deps="mediacodec" av1_mediacodec_decoder_deps="mediacodec"
@ -3387,6 +3393,8 @@ mjpeg_qsv_encoder_select="qsvenc"
mjpeg_vaapi_encoder_deps="VAEncPictureParameterBufferJPEG" mjpeg_vaapi_encoder_deps="VAEncPictureParameterBufferJPEG"
mjpeg_vaapi_encoder_select="cbs_jpeg jpegtables vaapi_encode" mjpeg_vaapi_encoder_select="cbs_jpeg jpegtables vaapi_encode"
mp3_mf_encoder_deps="mediafoundation" mp3_mf_encoder_deps="mediafoundation"
mp3_mediacodec_decoder_deps="mediacodec"
mp3_mediacodec_decoder_select="mpegaudioheader"
mpeg1_cuvid_decoder_deps="cuvid" mpeg1_cuvid_decoder_deps="cuvid"
mpeg1_v4l2m2m_decoder_deps="v4l2_m2m mpeg1_v4l2_m2m" mpeg1_v4l2m2m_decoder_deps="v4l2_m2m mpeg1_v4l2_m2m"
mpeg2_cuvid_decoder_deps="cuvid" mpeg2_cuvid_decoder_deps="cuvid"

View File

@ -197,6 +197,7 @@ OBJS-$(CONFIG_AAC_ENCODER) += aacenc.o aaccoder.o aacenctab.o \
aacenc_pred.o \ aacenc_pred.o \
psymodel.o kbdwin.o \ psymodel.o kbdwin.o \
mpeg4audio_sample_rates.o mpeg4audio_sample_rates.o
OBJS-$(CONFIG_AAC_MEDIACODEC_DECODER) += mediacodecdec.o
OBJS-$(CONFIG_AAC_MF_ENCODER) += mfenc.o mf_utils.o OBJS-$(CONFIG_AAC_MF_ENCODER) += mfenc.o mf_utils.o
OBJS-$(CONFIG_AASC_DECODER) += aasc.o msrledec.o OBJS-$(CONFIG_AASC_DECODER) += aasc.o msrledec.o
OBJS-$(CONFIG_AC3_DECODER) += ac3dec_float.o ac3dec_data.o ac3.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 \ celp_math.o acelp_filters.o \
acelp_vectors.o \ acelp_vectors.o \
acelp_pitch_delay.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_AMV_ENCODER) += mjpegenc.o mjpegenc_common.o
OBJS-$(CONFIG_ANM_DECODER) += anm.o OBJS-$(CONFIG_ANM_DECODER) += anm.o
OBJS-$(CONFIG_ANULL_DECODER) += null.o OBJS-$(CONFIG_ANULL_DECODER) += null.o
@ -521,6 +524,7 @@ OBJS-$(CONFIG_MP2FIXED_ENCODER) += mpegaudioenc_fixed.o mpegaudio.o \
mpegaudiotabs.o mpegaudiotabs.o
OBJS-$(CONFIG_MP2FLOAT_DECODER) += mpegaudiodec_float.o OBJS-$(CONFIG_MP2FLOAT_DECODER) += mpegaudiodec_float.o
OBJS-$(CONFIG_MP3_DECODER) += mpegaudiodec_fixed.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_MP3_MF_ENCODER) += mfenc.o mf_utils.o
OBJS-$(CONFIG_MP3ADU_DECODER) += mpegaudiodec_fixed.o OBJS-$(CONFIG_MP3ADU_DECODER) += mpegaudiodec_fixed.o
OBJS-$(CONFIG_MP3ADUFLOAT_DECODER) += mpegaudiodec_float.o OBJS-$(CONFIG_MP3ADUFLOAT_DECODER) += mpegaudiodec_float.o

View File

@ -822,8 +822,11 @@ extern const FFCodec ff_idf_decoder;
/* external libraries, that shouldn't be used by default if one of the /* external libraries, that shouldn't be used by default if one of the
* above is available */ * above is available */
extern const FFCodec ff_aac_mediacodec_decoder;
extern const FFCodec ff_aac_mf_encoder; extern const FFCodec ff_aac_mf_encoder;
extern const FFCodec ff_ac3_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_h263_v4l2m2m_encoder;
extern const FFCodec ff_libaom_av1_decoder; extern const FFCodec ff_libaom_av1_decoder;
/* hwaccel hooks only, so prefer external decoders */ /* 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_encoder;
extern const FFCodec ff_mjpeg_qsv_decoder; extern const FFCodec ff_mjpeg_qsv_decoder;
extern const FFCodec ff_mjpeg_vaapi_encoder; 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_mp3_mf_encoder;
extern const FFCodec ff_mpeg1_cuvid_decoder; extern const FFCodec ff_mpeg1_cuvid_decoder;
extern const FFCodec ff_mpeg2_cuvid_decoder; extern const FFCodec ff_mpeg2_cuvid_decoder;

View File

@ -291,7 +291,11 @@ done:
CONFIG_MPEG4_MEDIACODEC_DECODER || \ CONFIG_MPEG4_MEDIACODEC_DECODER || \
CONFIG_VP8_MEDIACODEC_DECODER || \ CONFIG_VP8_MEDIACODEC_DECODER || \
CONFIG_VP9_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) static int common_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format)
{ {
int ret = 0; int ret = 0;
@ -388,13 +392,55 @@ static av_cold int mediacodec_decode_init(AVCodecContext *avctx)
goto done; goto done;
break; break;
#endif #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: default:
av_assert0(0); av_assert0(0);
} }
ff_AMediaFormat_setString(format, "mime", codec_mime); 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)); s->ctx = av_mallocz(sizeof(*s->ctx));
if (!s->ctx) { if (!s->ctx) {
@ -611,3 +657,53 @@ DECLARE_MEDIACODEC_VDEC(vp9, "VP9", AV_CODEC_ID_VP9, NULL)
#if CONFIG_AV1_MEDIACODEC_DECODER #if CONFIG_AV1_MEDIACODEC_DECODER
DECLARE_MEDIACODEC_VDEC(av1, "AV1", AV_CODEC_ID_AV1, NULL) DECLARE_MEDIACODEC_VDEC(av1, "AV1", AV_CODEC_ID_AV1, NULL)
#endif #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

View File

@ -23,6 +23,7 @@
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include "libavutil/avassert.h"
#include "libavutil/common.h" #include "libavutil/common.h"
#include "libavutil/hwcontext_mediacodec.h" #include "libavutil/hwcontext_mediacodec.h"
#include "libavutil/mem.h" #include "libavutil/mem.h"
@ -30,6 +31,7 @@
#include "libavutil/pixfmt.h" #include "libavutil/pixfmt.h"
#include "libavutil/time.h" #include "libavutil/time.h"
#include "libavutil/timestamp.h" #include "libavutil/timestamp.h"
#include "libavutil/channel_layout.h"
#include "avcodec.h" #include "avcodec.h"
#include "decode.h" #include "decode.h"
@ -85,6 +87,107 @@
#define OUTPUT_DEQUEUE_TIMEOUT_US 8000 #define OUTPUT_DEQUEUE_TIMEOUT_US 8000
#define OUTPUT_DEQUEUE_BLOCK_TIMEOUT_US 1000000 #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 { enum {
COLOR_FormatYUV420Planar = 0x13, COLOR_FormatYUV420Planar = 0x13,
COLOR_FormatYUV420SemiPlanar = 0x15, COLOR_FormatYUV420SemiPlanar = 0x15,
@ -265,13 +368,79 @@ fail:
return ret; return ret;
} }
static int mediacodec_wrap_sw_buffer(AVCodecContext *avctx, static int mediacodec_wrap_sw_audio_buffer(AVCodecContext *avctx,
MediaCodecDecContext *s, MediaCodecDecContext *s,
uint8_t *data, uint8_t *data,
size_t size, size_t size,
ssize_t index, ssize_t index,
FFAMediaCodecBufferInfo *info, FFAMediaCodecBufferInfo *info,
AVFrame *frame) 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 ret = 0;
int status = 0; int status = 0;
@ -343,6 +512,22 @@ done:
return ret; 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 { \ #define AMEDIAFORMAT_GET_INT32(name, key, mandatory) do { \
int32_t value = 0; \ int32_t value = 0; \
if (ff_AMediaFormat_getInt32(s->format, key, &value)) { \ if (ff_AMediaFormat_getInt32(s->format, key, &value)) { \
@ -354,7 +539,7 @@ done:
} \ } \
} while (0) \ } 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 ret = 0;
int width = 0; int width = 0;
@ -463,6 +648,63 @@ fail:
return ret; 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) static int mediacodec_dec_flush_codec(AVCodecContext *avctx, MediaCodecDecContext *s)
{ {
FFAMediaCodec *codec = s->codec; FFAMediaCodec *codec = s->codec;
@ -486,11 +728,9 @@ static int mediacodec_dec_flush_codec(AVCodecContext *avctx, MediaCodecDecContex
return 0; return 0;
} }
int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s, static int mediacodec_dec_get_video_codec(AVCodecContext *avctx, MediaCodecDecContext *s,
const char *mime, FFAMediaFormat *format) const char *mime, FFAMediaFormat *format)
{ {
int ret = 0;
int status;
int profile; int profile;
enum AVPixelFormat pix_fmt; enum AVPixelFormat pix_fmt;
@ -499,12 +739,6 @@ int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s,
AV_PIX_FMT_NONE, 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); pix_fmt = ff_get_format(avctx, pix_fmts);
if (pix_fmt == AV_PIX_FMT_MEDIACODEC) { if (pix_fmt == AV_PIX_FMT_MEDIACODEC) {
AVMediaCodecContext *user_ctx = avctx->hwaccel_context; 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 // getCodecNameByType() can fail due to missing JVM, while NDK
// mediacodec can be used without JVM. // mediacodec can be used without JVM.
if (!s->use_ndk_codec) { if (!s->use_ndk_codec) {
ret = AVERROR_EXTERNAL; return AVERROR_EXTERNAL;
goto fail;
} }
av_log(avctx, AV_LOG_INFO, "Failed to getCodecNameByType\n"); av_log(avctx, AV_LOG_INFO, "Failed to getCodecNameByType\n");
} else { } else {
@ -556,10 +789,52 @@ int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s,
} }
if (!s->codec) { 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); 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; return AVERROR_EXTERNAL;
goto fail;
} }
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); status = ff_AMediaCodec_configure(s->codec, format, s->surface, NULL, 0);
if (status < 0) { if (status < 0) {
char *desc = ff_AMediaFormat_toString(format); char *desc = ff_AMediaFormat_toString(format);
@ -583,12 +858,14 @@ int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s,
goto fail; goto fail;
} }
s->format = ff_AMediaCodec_getOutputFormat(s->codec); if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
if (s->format) { s->format = ff_AMediaCodec_getOutputFormat(s->codec);
if ((ret = mediacodec_dec_parse_format(avctx, s)) < 0) { if (s->format) {
av_log(avctx, AV_LOG_ERROR, if ((ret = mediacodec_dec_parse_format(avctx, s)) < 0) {
"Failed to configure context\n"); av_log(avctx, AV_LOG_ERROR,
goto fail; "Failed to configure context\n");
goto fail;
}
} }
} }