summaryrefslogtreecommitdiff
path: root/media/libstagefright/wifi-display/source/PlaybackSession.cpp
diff options
context:
space:
mode:
authorAndreas Huber <andih@google.com>2012-09-25 14:20:08 -0700
committerAndreas Huber <andih@google.com>2012-09-25 16:05:09 -0700
commit28e17ed7e2fbb254fb99481b74db85e427c905ee (patch)
tree8d4af5c5b495452f048a58eccb07736f3c03a30a /media/libstagefright/wifi-display/source/PlaybackSession.cpp
parent92f655fe351a5f2eb7d36123d2b687d6e7e3e913 (diff)
Better transport stream timestamp handling.
Properly emit PCR and PMT/PAT updates every 0.1 secs. Don't stream RTCP unless requested by the dongle. related-to-bug: 7232540 Change-Id: Ie9a6949a074d86ab022adfab5d2811294ba746aa
Diffstat (limited to 'media/libstagefright/wifi-display/source/PlaybackSession.cpp')
-rw-r--r--media/libstagefright/wifi-display/source/PlaybackSession.cpp297
1 files changed, 196 insertions, 101 deletions
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
index be9b159d..99b30516 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
@@ -70,6 +70,9 @@ struct WifiDisplaySource::PlaybackSession::Track : public RefBase {
status_t start();
status_t stop();
+ void queueAccessUnit(const sp<ABuffer> &accessUnit);
+ sp<ABuffer> dequeueAccessUnit();
+
protected:
virtual ~Track();
@@ -82,6 +85,7 @@ private:
bool mStarted;
ssize_t mPacketizerTrackIndex;
bool mIsAudio;
+ List<sp<ABuffer> > mQueuedAccessUnits;
static bool IsAudioFormat(const sp<AMessage> &format);
@@ -182,6 +186,24 @@ status_t WifiDisplaySource::PlaybackSession::Track::stop() {
return err;
}
+void WifiDisplaySource::PlaybackSession::Track::queueAccessUnit(
+ const sp<ABuffer> &accessUnit) {
+ mQueuedAccessUnits.push_back(accessUnit);
+}
+
+sp<ABuffer> WifiDisplaySource::PlaybackSession::Track::dequeueAccessUnit() {
+ if (mQueuedAccessUnits.empty()) {
+ return NULL;
+ }
+
+ sp<ABuffer> accessUnit = *mQueuedAccessUnits.begin();
+ CHECK(accessUnit != NULL);
+
+ mQueuedAccessUnits.erase(mQueuedAccessUnits.begin());
+
+ return accessUnit;
+}
+
////////////////////////////////////////////////////////////////////////////////
WifiDisplaySource::PlaybackSession::PlaybackSession(
@@ -198,6 +220,7 @@ WifiDisplaySource::PlaybackSession::PlaybackSession(
mTSQueue(new ABuffer(12 + kMaxNumTSPacketsPerRTPPacket * 188)),
mPrevTimeUs(-1ll),
mTransportMode(TRANSPORT_UDP),
+ mAllTracksHavePacketizerIndex(false),
mRTPChannel(0),
mRTCPChannel(0),
mRTPPort(0),
@@ -675,129 +698,49 @@ void WifiDisplaySource::PlaybackSession::onMessageReceived(
if (what == Converter::kWhatAccessUnit) {
const sp<Track> &track = mTracks.valueFor(trackIndex);
- uint32_t flags = 0;
-
ssize_t packetizerTrackIndex = track->packetizerTrackIndex();
- if (packetizerTrackIndex < 0) {
- flags = TSPacketizer::EMIT_PAT_AND_PMT;
+ if (packetizerTrackIndex < 0) {
packetizerTrackIndex =
mPacketizer->addTrack(track->getFormat());
- if (packetizerTrackIndex >= 0) {
- track->setPacketizerTrackIndex(packetizerTrackIndex);
- }
- }
-
- if (packetizerTrackIndex >= 0) {
- sp<ABuffer> accessUnit;
- CHECK(msg->findBuffer("accessUnit", &accessUnit));
+ CHECK_GE(packetizerTrackIndex, 0);
- bool isHDCPEncrypted = false;
- uint64_t inputCTR;
- uint8_t HDCP_private_data[16];
- if (mHDCP != NULL && !track->isAudio()) {
- isHDCPEncrypted = true;
+ track->setPacketizerTrackIndex(packetizerTrackIndex);
- status_t err = mHDCP->encrypt(
- accessUnit->data(), accessUnit->size(),
- trackIndex /* streamCTR */,
- &inputCTR,
- accessUnit->data());
+ if (allTracksHavePacketizerIndex()) {
+ status_t err = packetizeQueuedAccessUnits();
if (err != OK) {
- ALOGI("Failed to HDCP-encrypt media data (err %d)",
- err);
-
// Inform WifiDisplaySource of our premature death
// (wish).
sp<AMessage> notify = mNotify->dup();
notify->setInt32("what", kWhatSessionDead);
notify->post();
+
break;
}
-
- HDCP_private_data[0] = 0x00;
-
- HDCP_private_data[1] =
- (((trackIndex >> 30) & 3) << 1) | 1;
-
- HDCP_private_data[2] = (trackIndex >> 22) & 0xff;
-
- HDCP_private_data[3] =
- (((trackIndex >> 15) & 0x7f) << 1) | 1;
-
- HDCP_private_data[4] = (trackIndex >> 7) & 0xff;
-
- HDCP_private_data[5] =
- ((trackIndex & 0x7f) << 1) | 1;
-
- HDCP_private_data[6] = 0x00;
-
- HDCP_private_data[7] =
- (((inputCTR >> 60) & 0x0f) << 1) | 1;
-
- HDCP_private_data[8] = (inputCTR >> 52) & 0xff;
-
- HDCP_private_data[9] =
- (((inputCTR >> 45) & 0x7f) << 1) | 1;
-
- HDCP_private_data[10] = (inputCTR >> 37) & 0xff;
-
- HDCP_private_data[11] =
- (((inputCTR >> 30) & 0x7f) << 1) | 1;
-
- HDCP_private_data[12] = (inputCTR >> 22) & 0xff;
-
- HDCP_private_data[13] =
- (((inputCTR >> 15) & 0x7f) << 1) | 1;
-
- HDCP_private_data[14] = (inputCTR >> 7) & 0xff;
-
- HDCP_private_data[15] =
- ((inputCTR & 0x7f) << 1) | 1;
-
- flags |= TSPacketizer::IS_ENCRYPTED;
}
+ }
- int64_t timeUs;
- CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
+ sp<ABuffer> accessUnit;
+ CHECK(msg->findBuffer("accessUnit", &accessUnit));
- if (mPrevTimeUs < 0ll || mPrevTimeUs + 100000ll >= timeUs) {
- flags |= TSPacketizer::EMIT_PCR;
- mPrevTimeUs = timeUs;
- }
+ if (!allTracksHavePacketizerIndex()) {
+ track->queueAccessUnit(accessUnit);
+ break;
+ }
- sp<ABuffer> packets;
- mPacketizer->packetize(
- packetizerTrackIndex, accessUnit, &packets, flags,
- isHDCPEncrypted ? NULL : HDCP_private_data,
- isHDCPEncrypted ? 0 : sizeof(HDCP_private_data));
-
- for (size_t offset = 0;
- offset < packets->size(); offset += 188) {
- bool lastTSPacket = (offset + 188 >= packets->size());
-
- // We're only going to flush video, audio packets are
- // much more frequent and would waste all that space
- // available in a full sized UDP packet.
- bool flush =
- lastTSPacket
- && ((ssize_t)trackIndex == mVideoTrackIndex);
-
- appendTSData(
- packets->data() + offset,
- 188,
- true /* timeDiscontinuity */,
- flush);
- }
+ status_t err = packetizeAccessUnit(trackIndex, accessUnit);
-#if LOG_TRANSPORT_STREAM
- if (mLogFile != NULL) {
- fwrite(packets->data(), 1, packets->size(), mLogFile);
- }
-#endif
+ if (err != OK) {
+ // Inform WifiDisplaySource of our premature death
+ // (wish).
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", kWhatSessionDead);
+ notify->post();
}
+ break;
} else if (what == Converter::kWhatEOS) {
CHECK_EQ(what, Converter::kWhatEOS);
@@ -1338,5 +1281,157 @@ status_t WifiDisplaySource::PlaybackSession::sendPacket(
return mNetSession->sendRequest(sessionID, data, size);
}
+bool WifiDisplaySource::PlaybackSession::allTracksHavePacketizerIndex() {
+ if (mAllTracksHavePacketizerIndex) {
+ return true;
+ }
+
+ for (size_t i = 0; i < mTracks.size(); ++i) {
+ if (mTracks.valueAt(i)->packetizerTrackIndex() < 0) {
+ return false;
+ }
+ }
+
+ mAllTracksHavePacketizerIndex = true;
+
+ return true;
+}
+
+status_t WifiDisplaySource::PlaybackSession::packetizeAccessUnit(
+ size_t trackIndex, const sp<ABuffer> &accessUnit) {
+ const sp<Track> &track = mTracks.valueFor(trackIndex);
+
+ uint32_t flags = 0;
+
+ bool isHDCPEncrypted = false;
+ uint64_t inputCTR;
+ uint8_t HDCP_private_data[16];
+ if (mHDCP != NULL && !track->isAudio()) {
+ isHDCPEncrypted = true;
+
+ status_t err = mHDCP->encrypt(
+ accessUnit->data(), accessUnit->size(),
+ trackIndex /* streamCTR */,
+ &inputCTR,
+ accessUnit->data());
+
+ if (err != OK) {
+ ALOGE("Failed to HDCP-encrypt media data (err %d)",
+ err);
+
+ return err;
+ }
+
+ HDCP_private_data[0] = 0x00;
+
+ HDCP_private_data[1] =
+ (((trackIndex >> 30) & 3) << 1) | 1;
+
+ HDCP_private_data[2] = (trackIndex >> 22) & 0xff;
+
+ HDCP_private_data[3] =
+ (((trackIndex >> 15) & 0x7f) << 1) | 1;
+
+ HDCP_private_data[4] = (trackIndex >> 7) & 0xff;
+
+ HDCP_private_data[5] =
+ ((trackIndex & 0x7f) << 1) | 1;
+
+ HDCP_private_data[6] = 0x00;
+
+ HDCP_private_data[7] =
+ (((inputCTR >> 60) & 0x0f) << 1) | 1;
+
+ HDCP_private_data[8] = (inputCTR >> 52) & 0xff;
+
+ HDCP_private_data[9] =
+ (((inputCTR >> 45) & 0x7f) << 1) | 1;
+
+ HDCP_private_data[10] = (inputCTR >> 37) & 0xff;
+
+ HDCP_private_data[11] =
+ (((inputCTR >> 30) & 0x7f) << 1) | 1;
+
+ HDCP_private_data[12] = (inputCTR >> 22) & 0xff;
+
+ HDCP_private_data[13] =
+ (((inputCTR >> 15) & 0x7f) << 1) | 1;
+
+ HDCP_private_data[14] = (inputCTR >> 7) & 0xff;
+
+ HDCP_private_data[15] =
+ ((inputCTR & 0x7f) << 1) | 1;
+
+ flags |= TSPacketizer::IS_ENCRYPTED;
+ }
+
+ int64_t timeUs = ALooper::GetNowUs();
+ if (mPrevTimeUs < 0ll || mPrevTimeUs + 100000ll <= timeUs) {
+ flags |= TSPacketizer::EMIT_PCR;
+ flags |= TSPacketizer::EMIT_PAT_AND_PMT;
+
+ mPrevTimeUs = timeUs;
+ }
+
+ sp<ABuffer> packets;
+ mPacketizer->packetize(
+ track->packetizerTrackIndex(), accessUnit, &packets, flags,
+ isHDCPEncrypted ? NULL : HDCP_private_data,
+ isHDCPEncrypted ? 0 : sizeof(HDCP_private_data));
+
+ for (size_t offset = 0;
+ offset < packets->size(); offset += 188) {
+ bool lastTSPacket = (offset + 188 >= packets->size());
+
+ // We're only going to flush video, audio packets are
+ // much more frequent and would waste all that space
+ // available in a full sized UDP packet.
+ bool flush =
+ lastTSPacket
+ && ((ssize_t)trackIndex == mVideoTrackIndex);
+
+ appendTSData(
+ packets->data() + offset,
+ 188,
+ true /* timeDiscontinuity */,
+ flush);
+ }
+
+#if LOG_TRANSPORT_STREAM
+ if (mLogFile != NULL) {
+ fwrite(packets->data(), 1, packets->size(), mLogFile);
+ }
+#endif
+
+ return OK;
+}
+
+status_t WifiDisplaySource::PlaybackSession::packetizeQueuedAccessUnits() {
+ for (;;) {
+ bool gotMoreData = false;
+ for (size_t i = 0; i < mTracks.size(); ++i) {
+ size_t trackIndex = mTracks.keyAt(i);
+ const sp<Track> &track = mTracks.valueAt(i);
+
+ sp<ABuffer> accessUnit = track->dequeueAccessUnit();
+ if (accessUnit != NULL) {
+ status_t err = packetizeAccessUnit(trackIndex, accessUnit);
+
+ if (err != OK) {
+ return err;
+ }
+
+ gotMoreData = true;
+ }
+ }
+
+ if (!gotMoreData) {
+ break;
+ }
+ }
+
+ return OK;
+}
+
} // namespace android