Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7f20f58a authored by Iris Chang's avatar Iris Chang Committed by Marco Nelissen
Browse files

mkv support more audio codec

mkv support audio codec as bellow:
codecID: A_MPEG/L2 (mp2 audio)
codecID: A_PCM/INT/LIT and A_PCM/INT/BIG (pcm audio)
codecID: A_MS/ACM
We can check the supported type in MKVWave2MIME function,
including mp2, mp3, pcm, adpcm.wma

Bug: 128470241
Test: play the files with new supported codecs and check
if they can be played normally.

Change-Id: Id92303b42ef763d1ce08a3c96265eda69622c79d
parent 1fd35418
Loading
Loading
Loading
Loading
+95 −5
Original line number Diff line number Diff line
@@ -150,6 +150,7 @@ private:
        AAC,
        HEVC,
        MP3,
        PCM,
        OTHER
    };

@@ -270,6 +271,8 @@ MatroskaSource::MatroskaSource(
        mType = AAC;
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
        mType = MP3;
    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
        mType = PCM;
    }
}

@@ -1054,6 +1057,27 @@ media_status_t MatroskaSource::read(
                    AMEDIAFORMAT_KEY_TARGET_TIME, targetSampleTimeUs);
        }

        if (mType == PCM) {
            int32_t bitPerFrame = 16;
            int32_t bigEndian = 0;
            AMediaFormat *meta = AMediaFormat_new();
            if (getFormat(meta) == AMEDIA_OK && meta != NULL) {
                AMediaFormat_getInt32(meta,
                                AMEDIAFORMAT_KEY_BITS_PER_SAMPLE, &bitPerFrame);
                AMediaFormat_getInt32(meta,
                                AMEDIAFORMAT_KEY_PCM_BIG_ENDIAN, &bigEndian);
            }
            AMediaFormat_delete(meta);
            if (bigEndian == 1 && bitPerFrame == 16) {
                // Big-endian -> little-endian
                uint16_t *dstData = (uint16_t *)frame->data() + frame->range_offset();
                uint16_t *srcData = (uint16_t *)frame->data() + frame->range_offset();
                for (size_t i = 0; i < frame->range_length() / 2; i++) {
                    dstData[i] = ntohs(srcData[i]);
                }
            }
        }

        *out = frame;

        return AMEDIA_OK;
@@ -1170,6 +1194,51 @@ media_status_t MatroskaSource::read(

////////////////////////////////////////////////////////////////////////////////

enum WaveID {
    MKV_RIFF_WAVE_FORMAT_PCM = 0x0001,
    MKV_RIFF_WAVE_FORMAT_ADPCM_ms = 0x0002,
    MKV_RIFF_WAVE_FORMAT_ADPCM_ima_wav = 0x0011,
    MKV_RIFF_WAVE_FORMAT_MPEGL12 = 0x0050,
    MKV_RIFF_WAVE_FORMAT_MPEGL3 = 0x0055,
    MKV_RIFF_WAVE_FORMAT_WMAV1 = 0x0160,
    MKV_RIFF_WAVE_FORMAT_WMAV2 = 0x0161,
};

static const char *MKVWave2MIME(uint16_t id) {
    switch (id) {
        case  MKV_RIFF_WAVE_FORMAT_MPEGL12:
            return MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II;

        case  MKV_RIFF_WAVE_FORMAT_MPEGL3:
            return MEDIA_MIMETYPE_AUDIO_MPEG;

        case MKV_RIFF_WAVE_FORMAT_PCM:
            return MEDIA_MIMETYPE_AUDIO_RAW;

        case MKV_RIFF_WAVE_FORMAT_ADPCM_ms:
            return MEDIA_MIMETYPE_AUDIO_MS_ADPCM;
        case MKV_RIFF_WAVE_FORMAT_ADPCM_ima_wav:
            return MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM;

        case MKV_RIFF_WAVE_FORMAT_WMAV1:
        case MKV_RIFF_WAVE_FORMAT_WMAV2:
            return MEDIA_MIMETYPE_AUDIO_WMA;
        default:
            ALOGW("unknown wave %x", id);
            return "";
    };
}

static bool isMkvAudioCsdSizeOK(const char* mime, size_t csdSize) {
    if ((!strcmp(mime, MEDIA_MIMETYPE_AUDIO_MS_ADPCM) && csdSize < 50) ||
        (!strcmp(mime, MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM) && csdSize < 20) ||
        (!strcmp(mime, MEDIA_MIMETYPE_AUDIO_WMA) && csdSize < 28) ||
        (!strcmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG) && csdSize < 30)) {
        return false;
    }
    return true;
}

// trans all FOURCC  to lower char
static uint32_t FourCCtoLower(uint32_t fourcc) {
    uint8_t ch_1 = tolower((fourcc >> 24) & 0xff);
@@ -2036,20 +2105,40 @@ void MatroskaExtractor::addTracks() {
                } else if (!strcmp("A_FLAC", codecID)) {
                    AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_FLAC);
                    err = addFlacMetadata(meta, codecPrivate, codecPrivateSize);
                } else if (!strcmp("A_MPEG/L2", codecID)) {
                    AMediaFormat_setString(meta,
                            AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II);
                } else if (!strcmp("A_PCM/INT/LIT", codecID) ||
                         !strcmp("A_PCM/INT/BIG", codecID)) {
                    AMediaFormat_setString(meta,
                            AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_RAW);
                    int32_t bigEndian = !strcmp("A_PCM/INT/BIG", codecID) ? 1: 0;
                    AMediaFormat_setInt32(meta,
                            AMEDIAFORMAT_KEY_PCM_BIG_ENDIAN, bigEndian);
                } else if ((!strcmp("A_MS/ACM", codecID))) {
                    if ((NULL == codecPrivate) || (codecPrivateSize < 30)) {
                    if ((NULL == codecPrivate) || (codecPrivateSize < 18)) {
                        ALOGW("unsupported audio: A_MS/ACM has no valid private data: %s, size: %zu",
                               codecPrivate == NULL ? "null" : "non-null", codecPrivateSize);
                        continue;
                    } else {
                        uint16_t ID = *(uint16_t *)codecPrivate;
                        if (ID == 0x0055) {
                            AMediaFormat_setString(meta,
                                    AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MPEG);
                        const char* mime = MKVWave2MIME(ID);
                        ALOGV("A_MS/ACM type is %s", mime);
                        if (!strncasecmp("audio/", mime, 6) &&
                                isMkvAudioCsdSizeOK(mime, codecPrivateSize)) {
                            AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, mime);
                        } else {
                            ALOGW("A_MS/ACM unsupported type , continue");
                            ALOGE("A_MS/ACM continue, unsupported audio type=%s, csdSize:%zu",
                                mime, codecPrivateSize);
                            continue;
                        }
                        if (!strcmp(mime, MEDIA_MIMETYPE_AUDIO_WMA)) {
                            addESDSFromCodecPrivate(meta, true, codecPrivate, codecPrivateSize);
                        } else if (!strcmp(mime, MEDIA_MIMETYPE_AUDIO_MS_ADPCM) ||
                                    !strcmp(mime, MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM)) {
                            uint32_t blockAlign = *(uint16_t*)(codecPrivate + 12);
                            addESDSFromCodecPrivate(meta, true, &blockAlign, sizeof(blockAlign));
                        }
                    }
                } else {
                    ALOGW("%s is not supported.", codecID);
@@ -2058,6 +2147,7 @@ void MatroskaExtractor::addTracks() {

                AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_SAMPLE_RATE, atrack->GetSamplingRate());
                AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, atrack->GetChannels());
                AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_BITS_PER_SAMPLE, atrack->GetBitDepth());
                break;
            }

+5 −1
Original line number Diff line number Diff line
@@ -1756,7 +1756,11 @@ void convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) {
                size_t outsize = reassembleAVCC(csd0, csd1, avcc.data());
                meta->setData(kKeyAVCC, kTypeAVCC, avcc.data(), outsize);
            }
        } else if (mime == MEDIA_MIMETYPE_AUDIO_AAC || mime == MEDIA_MIMETYPE_VIDEO_MPEG4) {
        } else if (mime == MEDIA_MIMETYPE_AUDIO_AAC ||
                mime == MEDIA_MIMETYPE_VIDEO_MPEG4 ||
                mime == MEDIA_MIMETYPE_AUDIO_WMA ||
                mime == MEDIA_MIMETYPE_AUDIO_MS_ADPCM ||
                mime == MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM) {
            std::vector<char> esds(csd0size + 31);
            // The written ESDS is actually for an audio stream, but it's enough
            // for transporting the CSD to muxers.
+4 −0
Original line number Diff line number Diff line
@@ -59,6 +59,10 @@ const char *MEDIA_MIMETYPE_AUDIO_EAC3_JOC = "audio/eac3-joc";
const char *MEDIA_MIMETYPE_AUDIO_AC4 = "audio/ac4";
const char *MEDIA_MIMETYPE_AUDIO_SCRAMBLED = "audio/scrambled";
const char *MEDIA_MIMETYPE_AUDIO_ALAC = "audio/alac";
const char *MEDIA_MIMETYPE_AUDIO_WMA = "audio/x-ms-wma";
const char *MEDIA_MIMETYPE_AUDIO_MS_ADPCM = "audio/x-adpcm-ms";
const char *MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM = "audio/x-adpcm-dvi-ima";


const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mp4";
const char *MEDIA_MIMETYPE_CONTAINER_WAV = "audio/x-wav";
+4 −0
Original line number Diff line number Diff line
@@ -61,6 +61,10 @@ extern const char *MEDIA_MIMETYPE_AUDIO_EAC3_JOC;
extern const char *MEDIA_MIMETYPE_AUDIO_AC4;
extern const char *MEDIA_MIMETYPE_AUDIO_SCRAMBLED;
extern const char *MEDIA_MIMETYPE_AUDIO_ALAC;
extern const char *MEDIA_MIMETYPE_AUDIO_WMA;
extern const char *MEDIA_MIMETYPE_AUDIO_MS_ADPCM;
extern const char *MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM;


extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG4;
extern const char *MEDIA_MIMETYPE_CONTAINER_WAV;