diff options
author | Andreas Huber <andih@google.com> | 2012-10-04 11:46:29 -0700 |
---|---|---|
committer | Andreas Huber <andih@google.com> | 2012-10-04 13:31:04 -0700 |
commit | e7bd24af08ef0722fb124a550662bcec48c56f86 (patch) | |
tree | a64d2bf14eab3008fb53f63ea8c01ba7c600c8e1 /media/libstagefright/wifi-display/source/Converter.cpp | |
parent | d69fd4d2567f9fce02252ce10d7ae3a28fc79e04 (diff) | |
download | frameworks_av-e7bd24af08ef0722fb124a550662bcec48c56f86.zip frameworks_av-e7bd24af08ef0722fb124a550662bcec48c56f86.tar.gz frameworks_av-e7bd24af08ef0722fb124a550662bcec48c56f86.tar.bz2 |
Optionally emit LPCM audio instead of using AAC in wifi display code
related-to-bug: 7248248
May decrease power usage at the cost of significantly increasing audio bitrate.
Use "adb shell setprop media.wfd.use-pcm-audio true"
to turn it on (must be done before connecting).
Change-Id: I7ebeadf3209e01522a2644948287b23d7c383c7e
Diffstat (limited to 'media/libstagefright/wifi-display/source/Converter.cpp')
-rw-r--r-- | media/libstagefright/wifi-display/source/Converter.cpp | 154 |
1 files changed, 145 insertions, 9 deletions
diff --git a/media/libstagefright/wifi-display/source/Converter.cpp b/media/libstagefright/wifi-display/source/Converter.cpp index 0e8c9af..a4a6f07 100644 --- a/media/libstagefright/wifi-display/source/Converter.cpp +++ b/media/libstagefright/wifi-display/source/Converter.cpp @@ -38,12 +38,14 @@ namespace android { Converter::Converter( const sp<AMessage> ¬ify, const sp<ALooper> &codecLooper, - const sp<AMessage> &format) + const sp<AMessage> &format, + bool usePCMAudio) : mInitCheck(NO_INIT), mNotify(notify), mCodecLooper(codecLooper), mInputFormat(format), mIsVideo(false), + mIsPCMAudio(usePCMAudio), mDoMoreWorkPending(false) #if ENABLE_SILENCE_DETECTION ,mFirstSilentFrameUs(-1ll) @@ -57,6 +59,8 @@ Converter::Converter( mIsVideo = true; } + CHECK(!usePCMAudio || !mIsVideo); + mInitCheck = initEncoder(); if (mInitCheck != OK) { @@ -109,7 +113,11 @@ status_t Converter::initEncoder() { AString outputMIME; bool isAudio = false; if (!strcasecmp(inputMIME.c_str(), MEDIA_MIMETYPE_AUDIO_RAW)) { - outputMIME = MEDIA_MIMETYPE_AUDIO_AAC; + if (mIsPCMAudio) { + outputMIME = MEDIA_MIMETYPE_AUDIO_RAW; + } else { + outputMIME = MEDIA_MIMETYPE_AUDIO_AAC; + } isAudio = true; } else if (!strcasecmp(inputMIME.c_str(), MEDIA_MIMETYPE_VIDEO_RAW)) { outputMIME = MEDIA_MIMETYPE_VIDEO_AVC; @@ -117,14 +125,21 @@ status_t Converter::initEncoder() { TRESPASS(); } - mEncoder = MediaCodec::CreateByType( - mCodecLooper, outputMIME.c_str(), true /* encoder */); + if (!mIsPCMAudio) { + mEncoder = MediaCodec::CreateByType( + mCodecLooper, outputMIME.c_str(), true /* encoder */); - if (mEncoder == NULL) { - return ERROR_UNSUPPORTED; + if (mEncoder == NULL) { + return ERROR_UNSUPPORTED; + } } mOutputFormat = mInputFormat->dup(); + + if (mIsPCMAudio) { + return OK; + } + mOutputFormat->setString("mime", outputMIME.c_str()); int32_t audioBitrate = getBitrate("media.wfd.audio-bitrate", 128000); @@ -197,7 +212,7 @@ void Converter::onMessageReceived(const sp<AMessage> &msg) { int32_t what; CHECK(msg->findInt32("what", &what)); - if (mEncoder == NULL) { + if (!mIsPCMAudio && mEncoder == NULL) { ALOGV("got msg '%s' after encoder shutdown.", msg->debugString().c_str()); @@ -317,8 +332,11 @@ void Converter::onMessageReceived(const sp<AMessage> &msg) { case kWhatShutdown: { ALOGI("shutting down encoder"); - mEncoder->release(); - mEncoder.clear(); + + if (mEncoder != NULL) { + mEncoder->release(); + mEncoder.clear(); + } AString mime; CHECK(mInputFormat->findString("mime", &mime)); @@ -332,6 +350,11 @@ void Converter::onMessageReceived(const sp<AMessage> &msg) { } void Converter::scheduleDoMoreWork() { + if (mIsPCMAudio) { + // There's no encoder involved in this case. + return; + } + if (mDoMoreWorkPending) { return; } @@ -350,7 +373,120 @@ void Converter::scheduleDoMoreWork() { #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() { + if (mIsPCMAudio) { + return feedRawAudioInputBuffers(); + } + while (!mInputBufferQueue.empty() && !mAvailEncoderInputIndices.empty()) { sp<ABuffer> buffer = *mInputBufferQueue.begin(); |