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

Commit dd432ce0 authored by Changwan Ryu's avatar Changwan Ryu Committed by Dongwon Kang
Browse files

[DO NOT MERGE] Support TS + AC3 for ATSC standard

Change-Id: I141667f3f54b242bafdf0ab9db86852c56f49ffa
parent 90903383
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -248,6 +248,8 @@ private:
            int32_t numChannels, int32_t sampleRate, int32_t bitRate,
            int32_t numChannels, int32_t sampleRate, int32_t bitRate,
            int32_t aacProfile, bool isADTS);
            int32_t aacProfile, bool isADTS);


    status_t setAC3Format(int32_t numChannels, int32_t sampleRate);

    void setG711Format(int32_t numChannels);
    void setG711Format(int32_t numChannels);


    status_t setVideoPortFormatType(
    status_t setVideoPortFormatType(
+51 −0
Original line number Original line Diff line number Diff line
@@ -40,7 +40,9 @@
#include <utils/Vector.h>
#include <utils/Vector.h>


#include <OMX_Audio.h>
#include <OMX_Audio.h>
#include <OMX_AudioExt.h>
#include <OMX_Component.h>
#include <OMX_Component.h>
#include <OMX_IndexExt.h>


#include "include/avc_utils.h"
#include "include/avc_utils.h"


@@ -528,6 +530,17 @@ status_t OMXCodec::configureCodec(const sp<MetaData> &meta) {
                    sampleRate,
                    sampleRate,
                    numChannels);
                    numChannels);
        }
        }
    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AC3, mMIME)) {
        int32_t numChannels;
        int32_t sampleRate;
        CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
        CHECK(meta->findInt32(kKeySampleRate, &sampleRate));

        status_t err = setAC3Format(numChannels, sampleRate);
        if (err != OK) {
            CODEC_LOGE("setAC3Format() failed (err = %d)", err);
            return err;
        }
    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_G711_ALAW, mMIME)
    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_G711_ALAW, mMIME)
            || !strcasecmp(MEDIA_MIMETYPE_AUDIO_G711_MLAW, mMIME)) {
            || !strcasecmp(MEDIA_MIMETYPE_AUDIO_G711_MLAW, mMIME)) {
        // These are PCM-like formats with a fixed sample rate but
        // These are PCM-like formats with a fixed sample rate but
@@ -1396,6 +1409,8 @@ void OMXCodec::setComponentRole(
            "audio_decoder.gsm", "audio_encoder.gsm" },
            "audio_decoder.gsm", "audio_encoder.gsm" },
        { MEDIA_MIMETYPE_VIDEO_MPEG2,
        { MEDIA_MIMETYPE_VIDEO_MPEG2,
            "video_decoder.mpeg2", "video_encoder.mpeg2" },
            "video_decoder.mpeg2", "video_encoder.mpeg2" },
        { MEDIA_MIMETYPE_AUDIO_AC3,
            "audio_decoder.ac3", "audio_encoder.ac3" },
    };
    };


    static const size_t kNumMimeToRole =
    static const size_t kNumMimeToRole =
@@ -3491,6 +3506,31 @@ status_t OMXCodec::setAACFormat(
    return OK;
    return OK;
}
}


status_t OMXCodec::setAC3Format(int32_t numChannels, int32_t sampleRate) {
    OMX_AUDIO_PARAM_ANDROID_AC3TYPE def;
    InitOMXParams(&def);
    def.nPortIndex = kPortIndexInput;

    status_t err = mOMX->getParameter(
            mNode,
            (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3,
            &def,
            sizeof(def));

    if (err != OK) {
        return err;
    }

    def.nChannels = numChannels;
    def.nSampleRate = sampleRate;

    return mOMX->setParameter(
            mNode,
            (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3,
            &def,
            sizeof(def));
}

void OMXCodec::setG711Format(int32_t numChannels) {
void OMXCodec::setG711Format(int32_t numChannels) {
    CHECK(!mIsEncoder);
    CHECK(!mIsEncoder);
    setRawAudioFormat(kPortIndexInput, 8000, numChannels);
    setRawAudioFormat(kPortIndexInput, 8000, numChannels);
@@ -4424,6 +4464,17 @@ void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) {
                mOutputFormat->setInt32(kKeyChannelCount, numChannels);
                mOutputFormat->setInt32(kKeyChannelCount, numChannels);
                mOutputFormat->setInt32(kKeySampleRate, sampleRate);
                mOutputFormat->setInt32(kKeySampleRate, sampleRate);
                mOutputFormat->setInt32(kKeyBitRate, bitRate);
                mOutputFormat->setInt32(kKeyBitRate, bitRate);
            } else if (audio_def->eEncoding ==
                    (OMX_AUDIO_CODINGTYPE)OMX_AUDIO_CodingAndroidAC3) {
                mOutputFormat->setCString(
                        kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AC3);
                int32_t numChannels, sampleRate, bitRate;
                inputFormat->findInt32(kKeyChannelCount, &numChannels);
                inputFormat->findInt32(kKeySampleRate, &sampleRate);
                inputFormat->findInt32(kKeyBitRate, &bitRate);
                mOutputFormat->setInt32(kKeyChannelCount, numChannels);
                mOutputFormat->setInt32(kKeySampleRate, sampleRate);
                mOutputFormat->setInt32(kKeyBitRate, bitRate);
            } else {
            } else {
                CHECK(!"Should not be here. Unknown audio encoding.");
                CHECK(!"Should not be here. Unknown audio encoding.");
            }
            }
+6 −0
Original line number Original line Diff line number Diff line
@@ -506,6 +506,11 @@ ATSParser::Stream::Stream(
                    ElementaryStreamQueue::PCM_AUDIO);
                    ElementaryStreamQueue::PCM_AUDIO);
            break;
            break;


        case STREAMTYPE_AC3:
            mQueue = new ElementaryStreamQueue(
                    ElementaryStreamQueue::AC3);
            break;

        default:
        default:
            break;
            break;
    }
    }
@@ -614,6 +619,7 @@ bool ATSParser::Stream::isAudio() const {
        case STREAMTYPE_MPEG2_AUDIO:
        case STREAMTYPE_MPEG2_AUDIO:
        case STREAMTYPE_MPEG2_AUDIO_ADTS:
        case STREAMTYPE_MPEG2_AUDIO_ADTS:
        case STREAMTYPE_PCM_AUDIO:
        case STREAMTYPE_PCM_AUDIO:
        case STREAMTYPE_AC3:
            return true;
            return true;


        default:
        default:
+4 −0
Original line number Original line Diff line number Diff line
@@ -88,6 +88,10 @@ struct ATSParser : public RefBase {
        STREAMTYPE_MPEG2_AUDIO_ADTS     = 0x0f,
        STREAMTYPE_MPEG2_AUDIO_ADTS     = 0x0f,
        STREAMTYPE_MPEG4_VIDEO          = 0x10,
        STREAMTYPE_MPEG4_VIDEO          = 0x10,
        STREAMTYPE_H264                 = 0x1b,
        STREAMTYPE_H264                 = 0x1b,

        // From ATSC A/53 Part 3:2009, 6.7.1
        STREAMTYPE_AC3                  = 0x81,

        STREAMTYPE_PCM_AUDIO            = 0x83,
        STREAMTYPE_PCM_AUDIO            = 0x83,
    };
    };


+190 −0
Original line number Original line Diff line number Diff line
@@ -56,6 +56,122 @@ void ElementaryStreamQueue::clear(bool clearFormat) {
    }
    }
}
}


// Parse AC3 header assuming the current ptr is start position of syncframe,
// update metadata only applicable, and return the payload size
static unsigned parseAC3SyncFrame(
        const uint8_t *ptr, size_t size, sp<MetaData> *metaData) {
    static const unsigned channelCountTable[] = {2, 1, 2, 3, 4, 4, 5, 6};
    static const unsigned samplingRateTable[] = {48000, 44100, 32000};
    static const unsigned rates[] = {32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256,
            320, 384, 448, 512, 576, 640};

    static const unsigned frameSizeTable[19][3] = {
        { 64, 69, 96 },
        { 80, 87, 120 },
        { 96, 104, 144 },
        { 112, 121, 168 },
        { 128, 139, 192 },
        { 160, 174, 240 },
        { 192, 208, 288 },
        { 224, 243, 336 },
        { 256, 278, 384 },
        { 320, 348, 480 },
        { 384, 417, 576 },
        { 448, 487, 672 },
        { 512, 557, 768 },
        { 640, 696, 960 },
        { 768, 835, 1152 },
        { 896, 975, 1344 },
        { 1024, 1114, 1536 },
        { 1152, 1253, 1728 },
        { 1280, 1393, 1920 },
    };

    ABitReader bits(ptr, size);
    unsigned syncStartPos = 0;  // in bytes
    if (bits.numBitsLeft() < 16) {
        return 0;
    }
    if (bits.getBits(16) != 0x0B77) {
        return 0;
    }

    if (bits.numBitsLeft() < 16 + 2 + 6 + 5 + 3 + 3) {
        ALOGV("Not enough bits left for further parsing");
        return 0;
    }
    bits.skipBits(16);  // crc1

    unsigned fscod = bits.getBits(2);
    if (fscod == 3) {
        ALOGW("Incorrect fscod in AC3 header");
        return 0;
    }

    unsigned frmsizecod = bits.getBits(6);
    if (frmsizecod > 37) {
        ALOGW("Incorrect frmsizecod in AC3 header");
        return 0;
    }

    unsigned bsid = bits.getBits(5);
    if (bsid > 8) {
        ALOGW("Incorrect bsid in AC3 header. Possibly E-AC-3?");
        return 0;
    }

    unsigned bsmod = bits.getBits(3);
    unsigned acmod = bits.getBits(3);
    unsigned cmixlev = 0;
    unsigned surmixlev = 0;
    unsigned dsurmod = 0;

    if ((acmod & 1) > 0 && acmod != 1) {
        if (bits.numBitsLeft() < 2) {
            return 0;
        }
        cmixlev = bits.getBits(2);
    }
    if ((acmod & 4) > 0) {
        if (bits.numBitsLeft() < 2) {
            return 0;
        }
        surmixlev = bits.getBits(2);
    }
    if (acmod == 2) {
        if (bits.numBitsLeft() < 2) {
            return 0;
        }
        dsurmod = bits.getBits(2);
    }

    if (bits.numBitsLeft() < 1) {
        return 0;
    }
    unsigned lfeon = bits.getBits(1);

    unsigned samplingRate = samplingRateTable[fscod];
    unsigned payloadSize = frameSizeTable[frmsizecod >> 1][fscod];
    if (fscod == 1) {
        payloadSize += frmsizecod & 1;
    }
    payloadSize <<= 1;  // convert from 16-bit words to bytes

    unsigned channelCount = channelCountTable[acmod] + lfeon;

    if (metaData != NULL) {
        (*metaData)->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AC3);
        (*metaData)->setInt32(kKeyChannelCount, channelCount);
        (*metaData)->setInt32(kKeySampleRate, samplingRate);
    }

    return payloadSize;
}

static bool IsSeeminglyValidAC3Header(const uint8_t *ptr, size_t size) {
    return parseAC3SyncFrame(ptr, size, NULL) > 0;
}

static bool IsSeeminglyValidADTSHeader(const uint8_t *ptr, size_t size) {
static bool IsSeeminglyValidADTSHeader(const uint8_t *ptr, size_t size) {
    if (size < 3) {
    if (size < 3) {
        // Not enough data to verify header.
        // Not enough data to verify header.
@@ -224,6 +340,33 @@ status_t ElementaryStreamQueue::appendData(
                break;
                break;
            }
            }


            case AC3:
            {
                uint8_t *ptr = (uint8_t *)data;

                ssize_t startOffset = -1;
                for (size_t i = 0; i < size; ++i) {
                    if (IsSeeminglyValidAC3Header(&ptr[i], size - i)) {
                        startOffset = i;
                        break;
                    }
                }

                if (startOffset < 0) {
                    return ERROR_MALFORMED;
                }

                if (startOffset > 0) {
                    ALOGI("found something resembling an AC3 syncword at "
                          "offset %d",
                          startOffset);
                }

                data = &ptr[startOffset];
                size -= startOffset;
                break;
            }

            case MPEG_AUDIO:
            case MPEG_AUDIO:
            {
            {
                uint8_t *ptr = (uint8_t *)data;
                uint8_t *ptr = (uint8_t *)data;
@@ -328,6 +471,8 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnit() {
            return dequeueAccessUnitH264();
            return dequeueAccessUnitH264();
        case AAC:
        case AAC:
            return dequeueAccessUnitAAC();
            return dequeueAccessUnitAAC();
        case AC3:
            return dequeueAccessUnitAC3();
        case MPEG_VIDEO:
        case MPEG_VIDEO:
            return dequeueAccessUnitMPEGVideo();
            return dequeueAccessUnitMPEGVideo();
        case MPEG4_VIDEO:
        case MPEG4_VIDEO:
@@ -340,6 +485,51 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnit() {
    }
    }
}
}


sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAC3() {
    unsigned syncStartPos = 0;  // in bytes
    unsigned payloadSize = 0;
    sp<MetaData> format = new MetaData;
    while (true) {
        if (syncStartPos + 2 >= mBuffer->size()) {
            return NULL;
        }

        payloadSize = parseAC3SyncFrame(
                mBuffer->data() + syncStartPos,
                mBuffer->size() - syncStartPos,
                &format);
        if (payloadSize > 0) {
            break;
        }
        ++syncStartPos;
    }

    if (mBuffer->size() < syncStartPos + payloadSize) {
        ALOGV("Not enough buffer size for AC3");
        return NULL;
    }

    if (mFormat == NULL) {
        mFormat = format;
    }

    sp<ABuffer> accessUnit = new ABuffer(syncStartPos + payloadSize);
    memcpy(accessUnit->data(), mBuffer->data(), syncStartPos + payloadSize);

    int64_t timeUs = fetchTimestamp(syncStartPos + payloadSize);
    CHECK_GE(timeUs, 0ll);
    accessUnit->meta()->setInt64("timeUs", timeUs);

    memmove(
            mBuffer->data(),
            mBuffer->data() + syncStartPos + payloadSize,
            mBuffer->size() - syncStartPos - payloadSize);

    mBuffer->setRange(0, mBuffer->size() - syncStartPos - payloadSize);

    return accessUnit;
}

sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitPCMAudio() {
sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitPCMAudio() {
    if (mBuffer->size() < 4) {
    if (mBuffer->size() < 4) {
        return NULL;
        return NULL;
Loading