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

Commit 1f915a85 authored by Andreas Huber's avatar Andreas Huber Committed by Android (Google) Code Review
Browse files

Merge "Optionally emit LPCM audio instead of using AAC in wifi display code" into jb-mr1-dev

parents 7ffab293 e7bd24af
Loading
Loading
Loading
Loading
+145 −9
Original line number Original line Diff line number Diff line
@@ -38,12 +38,14 @@ namespace android {
Converter::Converter(
Converter::Converter(
        const sp<AMessage> &notify,
        const sp<AMessage> &notify,
        const sp<ALooper> &codecLooper,
        const sp<ALooper> &codecLooper,
        const sp<AMessage> &format)
        const sp<AMessage> &format,
        bool usePCMAudio)
    : mInitCheck(NO_INIT),
    : mInitCheck(NO_INIT),
      mNotify(notify),
      mNotify(notify),
      mCodecLooper(codecLooper),
      mCodecLooper(codecLooper),
      mInputFormat(format),
      mInputFormat(format),
      mIsVideo(false),
      mIsVideo(false),
      mIsPCMAudio(usePCMAudio),
      mDoMoreWorkPending(false)
      mDoMoreWorkPending(false)
#if ENABLE_SILENCE_DETECTION
#if ENABLE_SILENCE_DETECTION
      ,mFirstSilentFrameUs(-1ll)
      ,mFirstSilentFrameUs(-1ll)
@@ -57,6 +59,8 @@ Converter::Converter(
        mIsVideo = true;
        mIsVideo = true;
    }
    }


    CHECK(!usePCMAudio || !mIsVideo);

    mInitCheck = initEncoder();
    mInitCheck = initEncoder();


    if (mInitCheck != OK) {
    if (mInitCheck != OK) {
@@ -109,7 +113,11 @@ status_t Converter::initEncoder() {
    AString outputMIME;
    AString outputMIME;
    bool isAudio = false;
    bool isAudio = false;
    if (!strcasecmp(inputMIME.c_str(), MEDIA_MIMETYPE_AUDIO_RAW)) {
    if (!strcasecmp(inputMIME.c_str(), MEDIA_MIMETYPE_AUDIO_RAW)) {
        if (mIsPCMAudio) {
            outputMIME = MEDIA_MIMETYPE_AUDIO_RAW;
        } else {
            outputMIME = MEDIA_MIMETYPE_AUDIO_AAC;
            outputMIME = MEDIA_MIMETYPE_AUDIO_AAC;
        }
        isAudio = true;
        isAudio = true;
    } else if (!strcasecmp(inputMIME.c_str(), MEDIA_MIMETYPE_VIDEO_RAW)) {
    } else if (!strcasecmp(inputMIME.c_str(), MEDIA_MIMETYPE_VIDEO_RAW)) {
        outputMIME = MEDIA_MIMETYPE_VIDEO_AVC;
        outputMIME = MEDIA_MIMETYPE_VIDEO_AVC;
@@ -117,14 +125,21 @@ status_t Converter::initEncoder() {
        TRESPASS();
        TRESPASS();
    }
    }


    if (!mIsPCMAudio) {
        mEncoder = MediaCodec::CreateByType(
        mEncoder = MediaCodec::CreateByType(
                mCodecLooper, outputMIME.c_str(), true /* encoder */);
                mCodecLooper, outputMIME.c_str(), true /* encoder */);


        if (mEncoder == NULL) {
        if (mEncoder == NULL) {
            return ERROR_UNSUPPORTED;
            return ERROR_UNSUPPORTED;
        }
        }
    }


    mOutputFormat = mInputFormat->dup();
    mOutputFormat = mInputFormat->dup();

    if (mIsPCMAudio) {
        return OK;
    }

    mOutputFormat->setString("mime", outputMIME.c_str());
    mOutputFormat->setString("mime", outputMIME.c_str());


    int32_t audioBitrate = getBitrate("media.wfd.audio-bitrate", 128000);
    int32_t audioBitrate = getBitrate("media.wfd.audio-bitrate", 128000);
@@ -197,7 +212,7 @@ void Converter::onMessageReceived(const sp<AMessage> &msg) {
            int32_t what;
            int32_t what;
            CHECK(msg->findInt32("what", &what));
            CHECK(msg->findInt32("what", &what));


            if (mEncoder == NULL) {
            if (!mIsPCMAudio && mEncoder == NULL) {
                ALOGV("got msg '%s' after encoder shutdown.",
                ALOGV("got msg '%s' after encoder shutdown.",
                      msg->debugString().c_str());
                      msg->debugString().c_str());


@@ -317,8 +332,11 @@ void Converter::onMessageReceived(const sp<AMessage> &msg) {
        case kWhatShutdown:
        case kWhatShutdown:
        {
        {
            ALOGI("shutting down encoder");
            ALOGI("shutting down encoder");

            if (mEncoder != NULL) {
                mEncoder->release();
                mEncoder->release();
                mEncoder.clear();
                mEncoder.clear();
            }


            AString mime;
            AString mime;
            CHECK(mInputFormat->findString("mime", &mime));
            CHECK(mInputFormat->findString("mime", &mime));
@@ -332,6 +350,11 @@ void Converter::onMessageReceived(const sp<AMessage> &msg) {
}
}


void Converter::scheduleDoMoreWork() {
void Converter::scheduleDoMoreWork() {
    if (mIsPCMAudio) {
        // There's no encoder involved in this case.
        return;
    }

    if (mDoMoreWorkPending) {
    if (mDoMoreWorkPending) {
        return;
        return;
    }
    }
@@ -350,7 +373,120 @@ void Converter::scheduleDoMoreWork() {
#endif
#endif
}
}


status_t Converter::feedRawAudioInputBuffers() {
    // Split incoming PCM audio into buffers of 6 AUs of 80 audio frames each
    // and add a 4 byte header according to the wifi display specs.

    while (!mInputBufferQueue.empty()) {
        sp<ABuffer> buffer = *mInputBufferQueue.begin();
        mInputBufferQueue.erase(mInputBufferQueue.begin());

        int16_t *ptr = (int16_t *)buffer->data();
        int16_t *stop = (int16_t *)(buffer->data() + buffer->size());
        while (ptr < stop) {
            *ptr = htons(*ptr);
            ++ptr;
        }

        static const size_t kFrameSize = 2 * sizeof(int16_t);  // stereo
        static const size_t kFramesPerAU = 80;
        static const size_t kNumAUsPerPESPacket = 6;

        if (mPartialAudioAU != NULL) {
            size_t bytesMissingForFullAU =
                kNumAUsPerPESPacket * kFramesPerAU * kFrameSize
                - mPartialAudioAU->size() + 4;

            size_t copy = buffer->size();
            if(copy > bytesMissingForFullAU) {
                copy = bytesMissingForFullAU;
            }

            memcpy(mPartialAudioAU->data() + mPartialAudioAU->size(),
                   buffer->data(),
                   copy);

            mPartialAudioAU->setRange(0, mPartialAudioAU->size() + copy);

            buffer->setRange(buffer->offset() + copy, buffer->size() - copy);

            int64_t timeUs;
            CHECK(buffer->meta()->findInt64("timeUs", &timeUs));

            int64_t copyUs = (int64_t)((copy / kFrameSize) * 1E6 / 48000.0);
            timeUs += copyUs;
            buffer->meta()->setInt64("timeUs", timeUs);

            if (bytesMissingForFullAU == copy) {
                sp<AMessage> notify = mNotify->dup();
                notify->setInt32("what", kWhatAccessUnit);
                notify->setBuffer("accessUnit", mPartialAudioAU);
                notify->post();

                mPartialAudioAU.clear();
            }
        }

        while (buffer->size() > 0) {
            sp<ABuffer> partialAudioAU =
                new ABuffer(
                        4
                        + kNumAUsPerPESPacket * kFrameSize * kFramesPerAU);

            uint8_t *ptr = partialAudioAU->data();
            ptr[0] = 0xa0;  // 10100000b
            ptr[1] = kNumAUsPerPESPacket;
            ptr[2] = 0;  // reserved, audio _emphasis_flag = 0

            static const unsigned kQuantizationWordLength = 0;  // 16-bit
            static const unsigned kAudioSamplingFrequency = 2;  // 48Khz
            static const unsigned kNumberOfAudioChannels = 1;  // stereo

            ptr[3] = (kQuantizationWordLength << 6)
                    | (kAudioSamplingFrequency << 3)
                    | kNumberOfAudioChannels;

            size_t copy = buffer->size();
            if (copy > partialAudioAU->size() - 4) {
                copy = partialAudioAU->size() - 4;
            }

            memcpy(&ptr[4], buffer->data(), copy);

            partialAudioAU->setRange(0, 4 + copy);
            buffer->setRange(buffer->offset() + copy, buffer->size() - copy);

            int64_t timeUs;
            CHECK(buffer->meta()->findInt64("timeUs", &timeUs));

            partialAudioAU->meta()->setInt64("timeUs", timeUs);

            int64_t copyUs = (int64_t)((copy / kFrameSize) * 1E6 / 48000.0);
            timeUs += copyUs;
            buffer->meta()->setInt64("timeUs", timeUs);

            if (copy == partialAudioAU->size() - 4) {
                sp<AMessage> notify = mNotify->dup();
                notify->setInt32("what", kWhatAccessUnit);
                notify->setBuffer("accessUnit", partialAudioAU);
                notify->post();

                partialAudioAU.clear();
                continue;
            }

            mPartialAudioAU = partialAudioAU;
        }
    }

    return OK;
}

status_t Converter::feedEncoderInputBuffers() {
status_t Converter::feedEncoderInputBuffers() {
    if (mIsPCMAudio) {
        return feedRawAudioInputBuffers();
    }

    while (!mInputBufferQueue.empty()
    while (!mInputBufferQueue.empty()
            && !mAvailEncoderInputIndices.empty()) {
            && !mAvailEncoderInputIndices.empty()) {
        sp<ABuffer> buffer = *mInputBufferQueue.begin();
        sp<ABuffer> buffer = *mInputBufferQueue.begin();
+12 −1
Original line number Original line Diff line number Diff line
@@ -18,6 +18,8 @@


#define CONVERTER_H_
#define CONVERTER_H_


#include "WifiDisplaySource.h"

#include <media/stagefright/foundation/AHandler.h>
#include <media/stagefright/foundation/AHandler.h>


namespace android {
namespace android {
@@ -34,7 +36,8 @@ struct Converter : public AHandler {
    Converter(
    Converter(
            const sp<AMessage> &notify,
            const sp<AMessage> &notify,
            const sp<ALooper> &codecLooper,
            const sp<ALooper> &codecLooper,
            const sp<AMessage> &format);
            const sp<AMessage> &format,
            bool usePCMAudio);


    status_t initCheck() const;
    status_t initCheck() const;


@@ -73,6 +76,7 @@ private:
    sp<ALooper> mCodecLooper;
    sp<ALooper> mCodecLooper;
    sp<AMessage> mInputFormat;
    sp<AMessage> mInputFormat;
    bool mIsVideo;
    bool mIsVideo;
    bool mIsPCMAudio;
    sp<AMessage> mOutputFormat;
    sp<AMessage> mOutputFormat;


    sp<MediaCodec> mEncoder;
    sp<MediaCodec> mEncoder;
@@ -92,6 +96,8 @@ private:
    bool mInSilentMode;
    bool mInSilentMode;
#endif
#endif


    sp<ABuffer> mPartialAudioAU;

    status_t initEncoder();
    status_t initEncoder();


    status_t feedEncoderInputBuffers();
    status_t feedEncoderInputBuffers();
@@ -101,6 +107,11 @@ private:


    void notifyError(status_t err);
    void notifyError(status_t err);


    // Packetizes raw PCM audio data available in mInputBufferQueue
    // into a format suitable for transport stream inclusion and
    // notifies the observer.
    status_t feedRawAudioInputBuffers();

    static bool IsSilence(const sp<ABuffer> &accessUnit);
    static bool IsSilence(const sp<ABuffer> &accessUnit);


    DISALLOW_EVIL_CONSTRUCTORS(Converter);
    DISALLOW_EVIL_CONSTRUCTORS(Converter);
+14 −10
Original line number Original line Diff line number Diff line
@@ -312,10 +312,11 @@ WifiDisplaySource::PlaybackSession::PlaybackSession(


status_t WifiDisplaySource::PlaybackSession::init(
status_t WifiDisplaySource::PlaybackSession::init(
        const char *clientIP, int32_t clientRtp, int32_t clientRtcp,
        const char *clientIP, int32_t clientRtp, int32_t clientRtcp,
        TransportMode transportMode) {
        TransportMode transportMode,
        bool usePCMAudio) {
    mClientIP = clientIP;
    mClientIP = clientIP;


    status_t err = setupPacketizer();
    status_t err = setupPacketizer(usePCMAudio);


    if (err != OK) {
    if (err != OK) {
        return err;
        return err;
@@ -823,7 +824,7 @@ void WifiDisplaySource::PlaybackSession::onMessageReceived(
    }
    }
}
}


status_t WifiDisplaySource::PlaybackSession::setupPacketizer() {
status_t WifiDisplaySource::PlaybackSession::setupPacketizer(bool usePCMAudio) {
    mPacketizer = new TSPacketizer;
    mPacketizer = new TSPacketizer;


    status_t err = addVideoSource();
    status_t err = addVideoSource();
@@ -832,12 +833,15 @@ status_t WifiDisplaySource::PlaybackSession::setupPacketizer() {
        return err;
        return err;
    }
    }


    return addAudioSource();
    return addAudioSource(usePCMAudio);
}
}


status_t WifiDisplaySource::PlaybackSession::addSource(
status_t WifiDisplaySource::PlaybackSession::addSource(
        bool isVideo, const sp<MediaSource> &source, bool isRepeaterSource,
        bool isVideo, const sp<MediaSource> &source, bool isRepeaterSource,
        size_t *numInputBuffers) {
        bool usePCMAudio, size_t *numInputBuffers) {
    CHECK(!usePCMAudio || !isVideo);
    CHECK(!isRepeaterSource || isVideo);

    sp<ALooper> pullLooper = new ALooper;
    sp<ALooper> pullLooper = new ALooper;
    pullLooper->setName("pull_looper");
    pullLooper->setName("pull_looper");


@@ -875,7 +879,7 @@ status_t WifiDisplaySource::PlaybackSession::addSource(
    notify->setSize("trackIndex", trackIndex);
    notify->setSize("trackIndex", trackIndex);


    sp<Converter> converter =
    sp<Converter> converter =
        new Converter(notify, codecLooper, format);
        new Converter(notify, codecLooper, format, usePCMAudio);


    if (converter->initCheck() != OK) {
    if (converter->initCheck() != OK) {
        return converter->initCheck();
        return converter->initCheck();
@@ -928,12 +932,12 @@ status_t WifiDisplaySource::PlaybackSession::addVideoSource() {
    size_t numInputBuffers;
    size_t numInputBuffers;
    status_t err = addSource(
    status_t err = addSource(
            true /* isVideo */, videoSource, true /* isRepeaterSource */,
            true /* isVideo */, videoSource, true /* isRepeaterSource */,
            &numInputBuffers);
            false /* usePCMAudio */, &numInputBuffers);
#else
#else
    size_t numInputBuffers;
    size_t numInputBuffers;
    status_t err = addSource(
    status_t err = addSource(
            true /* isVideo */, source, false /* isRepeaterSource */,
            true /* isVideo */, source, false /* isRepeaterSource */,
            &numInputBuffers);
            false /* usePCMAudio */, &numInputBuffers);
#endif
#endif


    if (err != OK) {
    if (err != OK) {
@@ -948,7 +952,7 @@ status_t WifiDisplaySource::PlaybackSession::addVideoSource() {
    return OK;
    return OK;
}
}


status_t WifiDisplaySource::PlaybackSession::addAudioSource() {
status_t WifiDisplaySource::PlaybackSession::addAudioSource(bool usePCMAudio) {
    sp<AudioSource> audioSource = new AudioSource(
    sp<AudioSource> audioSource = new AudioSource(
            AUDIO_SOURCE_REMOTE_SUBMIX,
            AUDIO_SOURCE_REMOTE_SUBMIX,
            48000 /* sampleRate */,
            48000 /* sampleRate */,
@@ -957,7 +961,7 @@ status_t WifiDisplaySource::PlaybackSession::addAudioSource() {
    if (audioSource->initCheck() == OK) {
    if (audioSource->initCheck() == OK) {
        return addSource(
        return addSource(
                false /* isVideo */, audioSource, false /* isRepeaterSource */,
                false /* isVideo */, audioSource, false /* isRepeaterSource */,
                NULL /* numInputBuffers */);
                usePCMAudio, NULL /* numInputBuffers */);
    }
    }


    ALOGW("Unable to instantiate audio source");
    ALOGW("Unable to instantiate audio source");
+5 −3
Original line number Original line Diff line number Diff line
@@ -50,7 +50,8 @@ struct WifiDisplaySource::PlaybackSession : public AHandler {
    };
    };
    status_t init(
    status_t init(
            const char *clientIP, int32_t clientRtp, int32_t clientRtcp,
            const char *clientIP, int32_t clientRtp, int32_t clientRtcp,
            TransportMode transportMode);
            TransportMode transportMode,
            bool usePCMAudio);


    void destroyAsync();
    void destroyAsync();


@@ -180,16 +181,17 @@ private:
    void addSDES(const sp<ABuffer> &buffer);
    void addSDES(const sp<ABuffer> &buffer);
    static uint64_t GetNowNTP();
    static uint64_t GetNowNTP();


    status_t setupPacketizer();
    status_t setupPacketizer(bool usePCMAudio);


    status_t addSource(
    status_t addSource(
            bool isVideo,
            bool isVideo,
            const sp<MediaSource> &source,
            const sp<MediaSource> &source,
            bool isRepeaterSource,
            bool isRepeaterSource,
            bool usePCMAudio,
            size_t *numInputBuffers);
            size_t *numInputBuffers);


    status_t addVideoSource();
    status_t addVideoSource();
    status_t addAudioSource();
    status_t addAudioSource(bool usePCMAudio);


    ssize_t appendTSData(
    ssize_t appendTSData(
            const void *data, size_t size, bool timeDiscontinuity, bool flush);
            const void *data, size_t size, bool timeDiscontinuity, bool flush);
+10 −1
Original line number Original line Diff line number Diff line
@@ -47,6 +47,7 @@ struct TSPacketizer::Track : public RefBase {
    bool isVideo() const;
    bool isVideo() const;


    bool isH264() const;
    bool isH264() const;
    bool isAAC() const;
    bool lacksADTSHeader() const;
    bool lacksADTSHeader() const;


    sp<ABuffer> prependCSD(const sp<ABuffer> &accessUnit) const;
    sp<ABuffer> prependCSD(const sp<ABuffer> &accessUnit) const;
@@ -139,6 +140,10 @@ bool TSPacketizer::Track::isH264() const {
    return !strcasecmp(mMIME.c_str(), MEDIA_MIMETYPE_VIDEO_AVC);
    return !strcasecmp(mMIME.c_str(), MEDIA_MIMETYPE_VIDEO_AVC);
}
}


bool TSPacketizer::Track::isAAC() const {
    return !strcasecmp(mMIME.c_str(), MEDIA_MIMETYPE_AUDIO_AAC);
}

bool TSPacketizer::Track::lacksADTSHeader() const {
bool TSPacketizer::Track::lacksADTSHeader() const {
    return mAudioLacksATDSHeaders;
    return mAudioLacksATDSHeaders;
}
}
@@ -247,6 +252,10 @@ ssize_t TSPacketizer::addTrack(const sp<AMessage> &format) {
        streamType = 0x0f;
        streamType = 0x0f;
        streamIDStart = 0xc0;
        streamIDStart = 0xc0;
        streamIDStop = 0xdf;
        streamIDStop = 0xdf;
    } else if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_RAW)) {
        streamType = 0x83;
        streamIDStart = 0xbd;
        streamIDStop = 0xbd;
    } else {
    } else {
        return ERROR_UNSUPPORTED;
        return ERROR_UNSUPPORTED;
    }
    }
@@ -298,7 +307,7 @@ status_t TSPacketizer::packetize(
            && IsIDR(accessUnit)) {
            && IsIDR(accessUnit)) {
        // prepend codec specific data, i.e. SPS and PPS.
        // prepend codec specific data, i.e. SPS and PPS.
        accessUnit = track->prependCSD(accessUnit);
        accessUnit = track->prependCSD(accessUnit);
    } else if (track->isAudio() && track->lacksADTSHeader()) {
    } else if (track->isAAC() && track->lacksADTSHeader()) {
        CHECK(!(flags & IS_ENCRYPTED));
        CHECK(!(flags & IS_ENCRYPTED));
        accessUnit = track->prependADTSHeader(accessUnit);
        accessUnit = track->prependADTSHeader(accessUnit);
    }
    }
Loading