summaryrefslogtreecommitdiffstats
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
parent92f655fe351a5f2eb7d36123d2b687d6e7e3e913 (diff)
downloadframeworks_av-28e17ed7e2fbb254fb99481b74db85e427c905ee.zip
frameworks_av-28e17ed7e2fbb254fb99481b74db85e427c905ee.tar.gz
frameworks_av-28e17ed7e2fbb254fb99481b74db85e427c905ee.tar.bz2
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
-rw-r--r--media/libstagefright/wifi-display/source/PlaybackSession.cpp297
-rw-r--r--media/libstagefright/wifi-display/source/PlaybackSession.h9
-rw-r--r--media/libstagefright/wifi-display/source/TSPacketizer.cpp12
-rw-r--r--media/libstagefright/wifi-display/source/WifiDisplaySource.cpp3
4 files changed, 210 insertions, 111 deletions
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
index be9b159..99b3051 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
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.h b/media/libstagefright/wifi-display/source/PlaybackSession.h
index f2090b4..6f74382 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.h
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.h
@@ -123,6 +123,8 @@ private:
AString mClientIP;
+ bool mAllTracksHavePacketizerIndex;
+
// in TCP mode
int32_t mRTPChannel;
int32_t mRTCPChannel;
@@ -196,6 +198,13 @@ private:
status_t onFinishPlay();
status_t onFinishPlay2();
+ bool allTracksHavePacketizerIndex();
+
+ status_t packetizeAccessUnit(
+ size_t trackIndex, const sp<ABuffer> &accessUnit);
+
+ status_t packetizeQueuedAccessUnits();
+
DISALLOW_EVIL_CONSTRUCTORS(PlaybackSession);
};
diff --git a/media/libstagefright/wifi-display/source/TSPacketizer.cpp b/media/libstagefright/wifi-display/source/TSPacketizer.cpp
index 613cc28..bd2f0c3 100644
--- a/media/libstagefright/wifi-display/source/TSPacketizer.cpp
+++ b/media/libstagefright/wifi-display/source/TSPacketizer.cpp
@@ -283,15 +283,15 @@ status_t TSPacketizer::packetize(
const uint8_t *PES_private_data, size_t PES_private_data_len) {
sp<ABuffer> accessUnit = _accessUnit;
+ int64_t timeUs;
+ CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
+
packets->clear();
if (trackIndex >= mTracks.size()) {
return -ERANGE;
}
- int64_t timeUs;
- CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
-
const sp<Track> &track = mTracks.itemAt(trackIndex);
if (track->isH264() && !(flags & IS_ENCRYPTED)) {
@@ -531,11 +531,7 @@ status_t TSPacketizer::packetize(
// reserved = b111111
// program_clock_reference_extension = b?????????
-#if 0
int64_t nowUs = ALooper::GetNowUs();
-#else
- int64_t nowUs = timeUs;
-#endif
uint64_t PCR = nowUs * 27; // PCR based on a 27MHz clock
uint64_t PCR_base = PCR / 300;
@@ -560,7 +556,7 @@ status_t TSPacketizer::packetize(
packetDataStart += 188;
}
- uint32_t PTS = (timeUs * 9ll) / 100ll;
+ uint64_t PTS = (timeUs * 9ll) / 100ll;
bool padding = (PES_packet_length < (188 - 10));
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
index 787ccc0..7f7aeac 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
@@ -876,7 +876,6 @@ status_t WifiDisplaySource::onSetupRequest(
} else if (sscanf(clientPort.c_str(), "%d", &clientRtp) == 1) {
// No RTCP.
clientRtcp = -1;
- clientRtcp = clientRtp + 1; // XXX
} else {
badRequest = true;
}
@@ -889,7 +888,7 @@ status_t WifiDisplaySource::onSetupRequest(
// The older LG dongles doesn't specify client_port=xxx apparently.
} else if (transport == "RTP/AVP/UDP;unicast") {
clientRtp = 19000;
- clientRtcp = clientRtp + 1;
+ clientRtcp = -1;
#endif
} else {
sendErrorResponse(sessionID, "461 Unsupported Transport", cseq);