Source code

Revision control

Copy as Markdown

Other Tools

diff --git a/media/ffvpx/libavcodec/allcodecs.c b/media/ffvpx/libavcodec/allcodecs.c
index 47eded261f17..2e92fab6a3b0 100644
--- a/media/ffvpx/libavcodec/allcodecs.c
+++ b/media/ffvpx/libavcodec/allcodecs.c
@@ -843,6 +843,7 @@ 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_flac_mediacodec_decoder;
extern const FFCodec ff_h263_v4l2m2m_encoder;
extern const FFCodec ff_libaom_av1_decoder;
/* hwaccel hooks only, so prefer external decoders */
@@ -904,8 +905,10 @@ extern const FFCodec ff_mpeg4_cuvid_decoder;
extern const FFCodec ff_mpeg4_mediacodec_decoder;
extern const FFCodec ff_mpeg4_mediacodec_encoder;
extern const FFCodec ff_mpeg4_v4l2m2m_encoder;
+extern const FFCodec ff_opus_mediacodec_decoder;
extern const FFCodec ff_prores_videotoolbox_encoder;
extern const FFCodec ff_vc1_cuvid_decoder;
+extern const FFCodec ff_vorbis_mediacodec_decoder;
extern const FFCodec ff_vp8_cuvid_decoder;
extern const FFCodec ff_vp8_mediacodec_decoder;
extern const FFCodec ff_vp8_mediacodec_encoder;
diff --git a/media/ffvpx/libavcodec/mediacodecdec.c b/media/ffvpx/libavcodec/mediacodecdec.c
index b9a76e806423..b2cb1c5da618 100644
--- a/media/ffvpx/libavcodec/mediacodecdec.c
+++ b/media/ffvpx/libavcodec/mediacodecdec.c
@@ -46,6 +46,15 @@
#include "hwconfig.h"
#include "internal.h"
#include "fffjni.h"
+#if CONFIG_VORBIS_MEDIACODEC_DECODER
+#include "xiph.h"
+#endif
+#if CONFIG_FLAC_MEDIACODEC_DECODER
+#include "flac.h"
+#endif
+#if CONFIG_OPUS_MEDIACODEC_DECODER || CONFIG_VORBIS_MEDIACODEC_DECODER
+#include "vorbis_data.h"
+#endif
#include "mediacodec_wrapper.h"
#include "mediacodecdec_common.h"
@@ -325,6 +334,72 @@ static int common_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format)
}
#endif
+#if CONFIG_OPUS_MEDIACODEC_DECODER
+static int opus_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format)
+{
+ uint64_t zero = 0;
+
+ if (!avctx->extradata || avctx->extradata_size < 19) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid Opus extradata\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ /* The codec delay and seek preroll are required, but pass zero for both
+ * so that the decoder does not discard any samples itself. The pre-skip
+ * is trimmed by the generic skip samples handling instead, and preroll
+ * after seeking is left to the caller as with the native decoder. */
+ ff_AMediaFormat_setBuffer(format, "csd-0", avctx->extradata, avctx->extradata_size);
+ ff_AMediaFormat_setBuffer(format, "csd-1", &zero, sizeof(zero));
+ ff_AMediaFormat_setBuffer(format, "csd-2", &zero, sizeof(zero));
+
+ return 0;
+}
+#endif
+
+#if CONFIG_VORBIS_MEDIACODEC_DECODER
+static int vorbis_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format)
+{
+ const uint8_t *header_start[3];
+ int header_len[3];
+
+ if (avpriv_split_xiph_headers(avctx->extradata, avctx->extradata_size, 30,
+ header_start, header_len) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid Vorbis extradata\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ ff_AMediaFormat_setBuffer(format, "csd-0", (void *)header_start[0], header_len[0]);
+ ff_AMediaFormat_setBuffer(format, "csd-1", (void *)header_start[2], header_len[2]);
+
+ return 0;
+}
+#endif
+
+#if CONFIG_FLAC_MEDIACODEC_DECODER
+static int flac_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format)
+{
+ uint8_t buf[8 + FLAC_STREAMINFO_SIZE];
+
+ if (!avctx->extradata || avctx->extradata_size < FLAC_STREAMINFO_SIZE) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid FLAC extradata\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (AV_RL32(avctx->extradata) == MKTAG('f','L','a','C')) {
+ ff_AMediaFormat_setBuffer(format, "csd-0", avctx->extradata, avctx->extradata_size);
+ return 0;
+ }
+
+ AV_WL32(buf, MKTAG('f','L','a','C'));
+ buf[4] = 0x80;
+ AV_WB24(buf + 5, FLAC_STREAMINFO_SIZE);
+ memcpy(buf + 8, avctx->extradata, FLAC_STREAMINFO_SIZE);
+ ff_AMediaFormat_setBuffer(format, "csd-0", buf, sizeof(buf));
+
+ return 0;
+}
+#endif
+
static av_cold int mediacodec_decode_init(AVCodecContext *avctx)
{
int ret;
@@ -448,6 +523,33 @@ static av_cold int mediacodec_decode_init(AVCodecContext *avctx)
if (ret < 0)
goto done;
break;
+#endif
+#if CONFIG_OPUS_MEDIACODEC_DECODER
+ case AV_CODEC_ID_OPUS:
+ codec_mime = "audio/opus";
+
+ ret = opus_set_extradata(avctx, format);
+ if (ret < 0)
+ goto done;
+ break;
+#endif
+#if CONFIG_VORBIS_MEDIACODEC_DECODER
+ case AV_CODEC_ID_VORBIS:
+ codec_mime = "audio/vorbis";
+
+ ret = vorbis_set_extradata(avctx, format);
+ if (ret < 0)
+ goto done;
+ break;
+#endif
+#if CONFIG_FLAC_MEDIACODEC_DECODER
+ case AV_CODEC_ID_FLAC:
+ codec_mime = "audio/flac";
+
+ ret = flac_set_extradata(avctx, format);
+ if (ret < 0)
+ goto done;
+ break;
#endif
default:
av_assert0(0);
@@ -478,6 +580,16 @@ static av_cold int mediacodec_decode_init(AVCodecContext *avctx)
s->ctx->delay_flush = s->delay_flush;
s->ctx->use_ndk_codec = s->use_ndk_codec;
+#if CONFIG_OPUS_MEDIACODEC_DECODER || CONFIG_VORBIS_MEDIACODEC_DECODER
+ /* Android outputs Vorbis and Opus channel mapping family 1 in the Vorbis
+ * channel order. */
+ if (avctx->codec_id == AV_CODEC_ID_VORBIS ||
+ (avctx->codec_id == AV_CODEC_ID_OPUS && avctx->extradata[18] == 1)) {
+ s->ctx->codec_ch_layouts = ff_vorbis_ch_layouts;
+ s->ctx->codec_ch_offsets = ff_vorbis_channel_layout_offsets;
+ }
+#endif
+
if ((ret = ff_mediacodec_dec_init(avctx, s->ctx, codec_mime, format)) < 0) {
s->ctx = NULL;
goto done;
@@ -591,6 +703,15 @@ static int mediacodec_receive_frame(AVCodecContext *avctx, AVFrame *frame)
} else if (ret < 0) {
return ret;
}
+
+ if (CONFIG_VORBIS_MEDIACODEC_DECODER && avctx->codec_id == AV_CODEC_ID_VORBIS) {
+ /* Android's Vorbis decoder expects each packet to be followed by
+ * the number of samples left on the page, or -1 if unknown. */
+ ret = av_grow_packet(&s->buffered_pkt, 4);
+ if (ret < 0)
+ return ret;
+ AV_WN32(s->buffered_pkt.data + s->buffered_pkt.size - 4, -1);
+ }
}
return AVERROR(EAGAIN);
@@ -738,6 +859,18 @@ DECLARE_MEDIACODEC_ADEC(amrwb, "AMR-WB", AV_CODEC_ID_AMR_WB, NULL)
DECLARE_MEDIACODEC_ADEC(mp3, "MP3", AV_CODEC_ID_MP3, NULL)
#endif
+#if CONFIG_OPUS_MEDIACODEC_DECODER
+DECLARE_MEDIACODEC_ADEC(opus, "Opus", AV_CODEC_ID_OPUS, NULL)
+#endif
+
+#if CONFIG_VORBIS_MEDIACODEC_DECODER
+DECLARE_MEDIACODEC_ADEC(vorbis, "Vorbis", AV_CODEC_ID_VORBIS, NULL)
+#endif
+
+#if CONFIG_FLAC_MEDIACODEC_DECODER
+DECLARE_MEDIACODEC_ADEC(flac, "FLAC", AV_CODEC_ID_FLAC, NULL)
+#endif
+
int moz_avcodec_mediacodec_is_eos(AVCodecContext* avctx) {
// Note that MediaCodecH264DecContext is used by all codec types.
MediaCodecH264DecContext *s = avctx->priv_data;
diff --git a/media/ffvpx/libavcodec/mediacodecdec_common.c b/media/ffvpx/libavcodec/mediacodecdec_common.c
index a0122f8fae61..d170810ffed6 100644
--- a/media/ffvpx/libavcodec/mediacodecdec_common.c
+++ b/media/ffvpx/libavcodec/mediacodecdec_common.c
@@ -428,7 +428,20 @@ static int mediacodec_wrap_sw_audio_buffer(AVCodecContext *avctx,
"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);
+ if (s->ch_offsets) {
+ const int channels = avctx->ch_layout.nb_channels;
+ const int stride = channels * sample_size;
+
+ for (int i = 0; i < frame->nb_samples; i++) {
+ const uint8_t *src = data + i * stride;
+ uint8_t *dst = frame->data[0] + i * stride;
+
+ for (int ch = 0; ch < channels; ch++)
+ memcpy(dst + ch * sample_size, src + s->ch_offsets[ch] * sample_size, sample_size);
+ }
+ } else {
+ memcpy(frame->data[0], data, info->size);
+ }
ret = 0;
done:
@@ -692,11 +705,18 @@ static int mediacodec_dec_parse_audio_format(AVCodecContext *avctx, MediaCodecDe
avctx->sample_rate = sample_rate;
+ s->ch_offsets = NULL;
AMEDIAFORMAT_GET_INT32(channel_mask, "channel-mask", 0);
- if (channel_mask)
+ if (channel_mask) {
av_channel_layout_from_mask(&avctx->ch_layout, mcdec_map_channel_mask(avctx, channel_mask));
- else
+ } else if (s->codec_ch_layouts && channel_count > 2 && channel_count <= 8) {
+ ret = av_channel_layout_copy(&avctx->ch_layout, &s->codec_ch_layouts[channel_count - 1]);
+ if (ret < 0)
+ goto fail;
+ s->ch_offsets = s->codec_ch_offsets[channel_count - 1];
+ } 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",
diff --git a/media/ffvpx/libavcodec/mediacodecdec_common.h b/media/ffvpx/libavcodec/mediacodecdec_common.h
index 0ab29036bd43..3d675508ce25 100644
--- a/media/ffvpx/libavcodec/mediacodecdec_common.h
+++ b/media/ffvpx/libavcodec/mediacodecdec_common.h
@@ -71,6 +71,13 @@ typedef struct MediaCodecDecContext {
atomic_int serial;
bool use_ndk_codec;
+
+ /* Codec specific channel layouts and the offsets to reorder them into
+ * the native order, indexed by channel count - 1, for 1 to 8 channels.
+ * Used when the output format has no channel mask. */
+ const AVChannelLayout *codec_ch_layouts;
+ const uint8_t (*codec_ch_offsets)[8];
+ const uint8_t *ch_offsets;
} MediaCodecDecContext;
int ff_mediacodec_dec_init(AVCodecContext *avctx,