summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorAndreas Huber <andih@google.com>2012-10-04 11:46:29 -0700
committerAndreas Huber <andih@google.com>2012-10-04 13:31:04 -0700
commite7bd24af08ef0722fb124a550662bcec48c56f86 (patch)
treea64d2bf14eab3008fb53f63ea8c01ba7c600c8e1 /media
parentd69fd4d2567f9fce02252ce10d7ae3a28fc79e04 (diff)
downloadframeworks_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')
-rw-r--r--media/libstagefright/wifi-display/source/Converter.cpp154
-rw-r--r--media/libstagefright/wifi-display/source/Converter.h13
-rw-r--r--media/libstagefright/wifi-display/source/PlaybackSession.cpp24
-rw-r--r--media/libstagefright/wifi-display/source/PlaybackSession.h8
-rw-r--r--media/libstagefright/wifi-display/source/TSPacketizer.cpp11
-rw-r--r--media/libstagefright/wifi-display/source/WifiDisplaySource.cpp14
-rw-r--r--media/libstagefright/wifi-display/source/WifiDisplaySource.h3
7 files changed, 200 insertions, 27 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> &notify,
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();
diff --git a/media/libstagefright/wifi-display/source/Converter.h b/media/libstagefright/wifi-display/source/Converter.h
index 8d45395..8dfff3d 100644
--- a/media/libstagefright/wifi-display/source/Converter.h
+++ b/media/libstagefright/wifi-display/source/Converter.h
@@ -18,6 +18,8 @@
#define CONVERTER_H_
+#include "WifiDisplaySource.h"
+
#include <media/stagefright/foundation/AHandler.h>
namespace android {
@@ -34,7 +36,8 @@ struct Converter : public AHandler {
Converter(
const sp<AMessage> &notify,
const sp<ALooper> &codecLooper,
- const sp<AMessage> &format);
+ const sp<AMessage> &format,
+ bool usePCMAudio);
status_t initCheck() const;
@@ -73,6 +76,7 @@ private:
sp<ALooper> mCodecLooper;
sp<AMessage> mInputFormat;
bool mIsVideo;
+ bool mIsPCMAudio;
sp<AMessage> mOutputFormat;
sp<MediaCodec> mEncoder;
@@ -92,6 +96,8 @@ private:
bool mInSilentMode;
#endif
+ sp<ABuffer> mPartialAudioAU;
+
status_t initEncoder();
status_t feedEncoderInputBuffers();
@@ -101,6 +107,11 @@ private:
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);
DISALLOW_EVIL_CONSTRUCTORS(Converter);
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
index ffdafed..6ef5e40 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
@@ -312,10 +312,11 @@ WifiDisplaySource::PlaybackSession::PlaybackSession(
status_t WifiDisplaySource::PlaybackSession::init(
const char *clientIP, int32_t clientRtp, int32_t clientRtcp,
- TransportMode transportMode) {
+ TransportMode transportMode,
+ bool usePCMAudio) {
mClientIP = clientIP;
- status_t err = setupPacketizer();
+ status_t err = setupPacketizer(usePCMAudio);
if (err != OK) {
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;
status_t err = addVideoSource();
@@ -832,12 +833,15 @@ status_t WifiDisplaySource::PlaybackSession::setupPacketizer() {
return err;
}
- return addAudioSource();
+ return addAudioSource(usePCMAudio);
}
status_t WifiDisplaySource::PlaybackSession::addSource(
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;
pullLooper->setName("pull_looper");
@@ -875,7 +879,7 @@ status_t WifiDisplaySource::PlaybackSession::addSource(
notify->setSize("trackIndex", trackIndex);
sp<Converter> converter =
- new Converter(notify, codecLooper, format);
+ new Converter(notify, codecLooper, format, usePCMAudio);
if (converter->initCheck() != OK) {
return converter->initCheck();
@@ -928,12 +932,12 @@ status_t WifiDisplaySource::PlaybackSession::addVideoSource() {
size_t numInputBuffers;
status_t err = addSource(
true /* isVideo */, videoSource, true /* isRepeaterSource */,
- &numInputBuffers);
+ false /* usePCMAudio */, &numInputBuffers);
#else
size_t numInputBuffers;
status_t err = addSource(
true /* isVideo */, source, false /* isRepeaterSource */,
- &numInputBuffers);
+ false /* usePCMAudio */, &numInputBuffers);
#endif
if (err != OK) {
@@ -948,7 +952,7 @@ status_t WifiDisplaySource::PlaybackSession::addVideoSource() {
return OK;
}
-status_t WifiDisplaySource::PlaybackSession::addAudioSource() {
+status_t WifiDisplaySource::PlaybackSession::addAudioSource(bool usePCMAudio) {
sp<AudioSource> audioSource = new AudioSource(
AUDIO_SOURCE_REMOTE_SUBMIX,
48000 /* sampleRate */,
@@ -957,7 +961,7 @@ status_t WifiDisplaySource::PlaybackSession::addAudioSource() {
if (audioSource->initCheck() == OK) {
return addSource(
false /* isVideo */, audioSource, false /* isRepeaterSource */,
- NULL /* numInputBuffers */);
+ usePCMAudio, NULL /* numInputBuffers */);
}
ALOGW("Unable to instantiate audio source");
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.h b/media/libstagefright/wifi-display/source/PlaybackSession.h
index 5d4bde8..4bbc3f0 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.h
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.h
@@ -50,7 +50,8 @@ struct WifiDisplaySource::PlaybackSession : public AHandler {
};
status_t init(
const char *clientIP, int32_t clientRtp, int32_t clientRtcp,
- TransportMode transportMode);
+ TransportMode transportMode,
+ bool usePCMAudio);
void destroyAsync();
@@ -180,16 +181,17 @@ private:
void addSDES(const sp<ABuffer> &buffer);
static uint64_t GetNowNTP();
- status_t setupPacketizer();
+ status_t setupPacketizer(bool usePCMAudio);
status_t addSource(
bool isVideo,
const sp<MediaSource> &source,
bool isRepeaterSource,
+ bool usePCMAudio,
size_t *numInputBuffers);
status_t addVideoSource();
- status_t addAudioSource();
+ status_t addAudioSource(bool usePCMAudio);
ssize_t appendTSData(
const void *data, size_t size, bool timeDiscontinuity, bool flush);
diff --git a/media/libstagefright/wifi-display/source/TSPacketizer.cpp b/media/libstagefright/wifi-display/source/TSPacketizer.cpp
index e5abd57..7e66072 100644
--- a/media/libstagefright/wifi-display/source/TSPacketizer.cpp
+++ b/media/libstagefright/wifi-display/source/TSPacketizer.cpp
@@ -47,6 +47,7 @@ struct TSPacketizer::Track : public RefBase {
bool isVideo() const;
bool isH264() const;
+ bool isAAC() const;
bool lacksADTSHeader() 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);
}
+bool TSPacketizer::Track::isAAC() const {
+ return !strcasecmp(mMIME.c_str(), MEDIA_MIMETYPE_AUDIO_AAC);
+}
+
bool TSPacketizer::Track::lacksADTSHeader() const {
return mAudioLacksATDSHeaders;
}
@@ -247,6 +252,10 @@ ssize_t TSPacketizer::addTrack(const sp<AMessage> &format) {
streamType = 0x0f;
streamIDStart = 0xc0;
streamIDStop = 0xdf;
+ } else if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_RAW)) {
+ streamType = 0x83;
+ streamIDStart = 0xbd;
+ streamIDStop = 0xbd;
} else {
return ERROR_UNSUPPORTED;
}
@@ -298,7 +307,7 @@ status_t TSPacketizer::packetize(
&& IsIDR(accessUnit)) {
// prepend codec specific data, i.e. SPS and PPS.
accessUnit = track->prependCSD(accessUnit);
- } else if (track->isAudio() && track->lacksADTSHeader()) {
+ } else if (track->isAAC() && track->lacksADTSHeader()) {
CHECK(!(flags & IS_ENCRYPTED));
accessUnit = track->prependADTSHeader(accessUnit);
}
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
index b0aaf3b..d856bac 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
@@ -46,6 +46,7 @@ WifiDisplaySource::WifiDisplaySource(
mClient(client),
mSessionID(0),
mStopReplyID(0),
+ mUsingPCMAudio(false),
mClientSessionID(0),
mReaperPending(false),
mNextCSeq(1)
@@ -531,6 +532,11 @@ status_t WifiDisplaySource::sendM4(int32_t sessionID) {
transportString = "TCP";
}
+ if (property_get("media.wfd.use-pcm-audio", val, NULL)
+ && (!strcasecmp("true", val) || !strcmp("1", val))) {
+ ALOGI("Using PCM audio.");
+ mUsingPCMAudio = true;
+ }
// For 720p60:
// use "30 00 02 02 00000040 00000000 00000000 00 0000 0000 00 none none\r\n"
// For 720p30:
@@ -540,9 +546,12 @@ status_t WifiDisplaySource::sendM4(int32_t sessionID) {
AString body = StringPrintf(
"wfd_video_formats: "
"28 00 02 02 00000020 00000000 00000000 00 0000 0000 00 none none\r\n"
- "wfd_audio_codecs: AAC 00000001 00\r\n" // 2 ch AAC 48kHz
+ "wfd_audio_codecs: %s\r\n"
"wfd_presentation_URL: rtsp://%s/wfd1.0/streamid=0 none\r\n"
"wfd_client_rtp_ports: RTP/AVP/%s;unicast 19000 0 mode=play\r\n",
+ (mUsingPCMAudio
+ ? "LPCM 00000002 00" // 2 ch PCM 48kHz
+ : "AAC 00000001 00"), // 2 ch AAC 48kHz
mClientInfo.mLocalIP.c_str(), transportString.c_str());
AString request = "SET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
@@ -1000,7 +1009,8 @@ status_t WifiDisplaySource::onSetupRequest(
mClientInfo.mRemoteIP.c_str(),
clientRtp,
clientRtcp,
- transportMode);
+ transportMode,
+ mUsingPCMAudio);
if (err != OK) {
looper()->unregisterHandler(playbackSession->id());
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.h b/media/libstagefright/wifi-display/source/WifiDisplaySource.h
index c30e3cb..0692cde 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.h
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.h
@@ -26,7 +26,7 @@
namespace android {
-#define REQUIRE_HDCP 1
+#define REQUIRE_HDCP 1
struct IHDCP;
struct IRemoteDisplayClient;
@@ -114,6 +114,7 @@ private:
uint32_t mStopReplyID;
+ bool mUsingPCMAudio;
int32_t mClientSessionID;
struct ClientInfo {