diff options
author | Andreas Huber <andih@google.com> | 2013-03-05 10:56:27 -0800 |
---|---|---|
committer | Andreas Huber <andih@google.com> | 2013-03-05 13:07:19 -0800 |
commit | a556c4822fc205db0d27834ba5b637c351d73ffa (patch) | |
tree | 814471eaca96e0c8e7237563ff3f303171ba8546 /media/libstagefright/wifi-display/MediaSender.cpp | |
parent | d573622dc001c23223cb26b1f55fb75be189e77d (diff) | |
download | frameworks_av-a556c4822fc205db0d27834ba5b637c351d73ffa.zip frameworks_av-a556c4822fc205db0d27834ba5b637c351d73ffa.tar.gz frameworks_av-a556c4822fc205db0d27834ba5b637c351d73ffa.tar.bz2 |
Squashed commit of the following:
commit e5919b1f57ea61fa1d380dfdb4e3e832ce73d79d
Author: Andreas Huber <andih@google.com>
Date: Wed Feb 27 16:38:48 2013 -0800
Configure TCP datagram sockets to be TCP_NODELAY.
Change-Id: Ia724a81e6e27dccd00ac84603e712d69ca77a0cd
commit 1b52b393183db8a6dc000a7c31baac544ccfc50c
Author: Andreas Huber <andih@google.com>
Date: Wed Feb 27 14:26:01 2013 -0800
Send IDR frame requests on packet loss.
Change-Id: I53b7fb85cbd6923491113b93ec3e2175726d654a
commit 68d76b4b3a0181b30abc57cd2915273210530a6d
Author: Andreas Huber <andih@google.com>
Date: Tue Feb 26 15:12:34 2013 -0800
Revive TunnelRenderer
Change-Id: I8c5a9d982793b1c5b841c828227b354f1dab618c
commit 3df28a8e9d8bcdc1430016bb088d097eca653b56
Author: Andreas Huber <andih@google.com>
Date: Tue Feb 26 13:53:14 2013 -0800
Disable suspension of video updates.
Change-Id: I7e3a16b8d7dd7a55d9f962a2236388931f664106
commit 2ec7a79de019a26ec415016c1478afd762f069cd
Author: Andreas Huber <andih@google.com>
Date: Tue Feb 26 08:54:40 2013 -0800
Adds an SNTP client to wfd.
Change-Id: Icd7d6104e951e1443e4c1b81ccf6b3731d79d3ec
commit c81c3bb5725bb4079a4d7fb02151ad0bb540632f
Author: Andreas Huber <andih@google.com>
Date: Mon Feb 25 10:00:58 2013 -0800
Squashed commit of the following:
commit b83a4ec96659ef6f6b7c2090fdd866abe3ab78ba
Author: Andreas Huber <andih@google.com>
Date: Mon Feb 25 09:28:11 2013 -0800
Some reorganization of the rtp code, renamed StreamHub -> MediaSender
Change-Id: I8cf67444960e60426bf74880af1acce41e8b2fef
commit 7769cbd739f2a67c58e0c6a7b1a21a12210c7c4d
Author: Andreas Huber <andih@google.com>
Date: Fri Feb 22 16:12:18 2013 -0800
Choose a smaller MTU to avoid fragmented IPv4 packets, fix AVC assembler.
Change-Id: I274b3cc1483c4e9f4d146dbf9f3d9f7557ef7ef9
commit 1f687ee80a88b56d614c2cf408ff729114ff86a0
Author: Andreas Huber <andih@google.com>
Date: Fri Feb 22 11:38:31 2013 -0800
better reporting.
Change-Id: I67f0bb51f106ea77f5cc75938b053c8e8e8f688e
commit 7950c1cd59213eb5f281fcde44a772ecffae473d
Author: Andreas Huber <andih@google.com>
Date: Fri Feb 22 09:07:41 2013 -0800
stuff
Change-Id: Ib99416366d3eec6e6ad69b4d791a8a9408410f3b
commit 33c09045b0f86fcaa4619cbd679b47a074f71231
Author: Andreas Huber <andih@google.com>
Date: Thu Feb 21 15:54:01 2013 -0800
Render frames according to their timestamps.
Change-Id: I8143a95cffe775799d6a4bb093558bd7abb1f063
commit d8b6daae2160bf1c016d7c6251256b46bb89db42
Author: Andreas Huber <andih@google.com>
Date: Thu Feb 21 15:01:27 2013 -0800
Better packet-lost logic.
Change-Id: I611eee5a42bd089638cf45b0e16f628ff2a955ab
commit 782c6b15717e2d062d96665a089d06c0577733d0
Author: Andreas Huber <andih@google.com>
Date: Wed Feb 20 15:06:47 2013 -0800
Add a dedicated looper for the MediaReceiver
Change-Id: I3b79cad367fb69c9a160a8d009af8c5f5142b98e
commit 4c7b8b10861674b773270103bcabd1a99486a691
Author: Andreas Huber <andih@google.com>
Date: Wed Feb 20 14:30:28 2013 -0800
Tweaks to RTPSender and RTPReceiver
Change-Id: Ib535552f289a26cfead6df8c63e4c63d3987d4e9
commit 39226b28177a816cda5c67b321745d396b18277d
Author: Andreas Huber <andih@google.com>
Date: Tue Feb 19 08:48:25 2013 -0800
Playing around with non muxed delivery
Change-Id: I845375f6938d04bc30502840c2ceb7688dc9b237
commit c16d21de75d8ecdbcd9abce14934afe484970061
Author: Andreas Huber <andih@google.com>
Date: Wed Feb 13 14:43:35 2013 -0800
A more solid base for RTP communication.
Change-Id: I52033eeb0feba0ff029d61553a821c82f2fa1c3f
Change-Id: I57e3bcfc1c59a012b15aaaa42ed81f09c34c26bb
Change-Id: I4b09db4a44d0eeded7a1658f6dc6c97d4b8be720
Diffstat (limited to 'media/libstagefright/wifi-display/MediaSender.cpp')
-rw-r--r-- | media/libstagefright/wifi-display/MediaSender.cpp | 443 |
1 files changed, 443 insertions, 0 deletions
diff --git a/media/libstagefright/wifi-display/MediaSender.cpp b/media/libstagefright/wifi-display/MediaSender.cpp new file mode 100644 index 0000000..900aa82 --- /dev/null +++ b/media/libstagefright/wifi-display/MediaSender.cpp @@ -0,0 +1,443 @@ +/* + * Copyright 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "MediaSender" +#include <utils/Log.h> + +#include "MediaSender.h" + +#include "ANetworkSession.h" +#include "rtp/RTPSender.h" +#include "source/TSPacketizer.h" + +#include "include/avc_utils.h" + +#include <media/IHDCP.h> +#include <media/stagefright/foundation/ABuffer.h> +#include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/foundation/AMessage.h> + +namespace android { + +MediaSender::MediaSender( + const sp<ANetworkSession> &netSession, + const sp<AMessage> ¬ify) + : mNetSession(netSession), + mNotify(notify), + mMode(MODE_UNDEFINED), + mGeneration(0), + mPrevTimeUs(-1ll), + mInitDoneCount(0) { +} + +MediaSender::~MediaSender() { +} + +status_t MediaSender::setHDCP(const sp<IHDCP> &hdcp) { + if (mMode != MODE_UNDEFINED) { + return INVALID_OPERATION; + } + + mHDCP = hdcp; + + return OK; +} + +ssize_t MediaSender::addTrack(const sp<AMessage> &format, uint32_t flags) { + if (mMode != MODE_UNDEFINED) { + return INVALID_OPERATION; + } + + TrackInfo info; + info.mFormat = format; + info.mFlags = flags; + info.mPacketizerTrackIndex = -1; + + AString mime; + CHECK(format->findString("mime", &mime)); + info.mIsAudio = !strncasecmp("audio/", mime.c_str(), 6); + + size_t index = mTrackInfos.size(); + mTrackInfos.push_back(info); + + return index; +} + +status_t MediaSender::initAsync( + ssize_t trackIndex, + RTPSender::TransportMode transportMode, + const char *remoteHost, + int32_t remoteRTPPort, + int32_t remoteRTCPPort, + int32_t *localRTPPort) { + if (trackIndex < 0) { + if (mMode != MODE_UNDEFINED) { + return INVALID_OPERATION; + } + + mTSPacketizer = new TSPacketizer; + + status_t err = OK; + for (size_t i = 0; i < mTrackInfos.size(); ++i) { + TrackInfo *info = &mTrackInfos.editItemAt(i); + + sp<AMessage> trackFormat = info->mFormat; + if (mHDCP != NULL && !info->mIsAudio) { + // HDCP2.0 _and_ HDCP 2.1 specs say to set the version + // inside the HDCP descriptor to 0x20!!! + trackFormat->setInt32("hdcp-version", 0x20); + } + + ssize_t packetizerTrackIndex = + mTSPacketizer->addTrack(trackFormat); + + if (packetizerTrackIndex < 0) { + err = packetizerTrackIndex; + break; + } + + info->mPacketizerTrackIndex = packetizerTrackIndex; + } + + if (err == OK) { + sp<AMessage> notify = new AMessage(kWhatSenderNotify, id()); + notify->setInt32("generation", mGeneration); + mTSSender = new RTPSender(mNetSession, notify); + looper()->registerHandler(mTSSender); + + err = mTSSender->initAsync( + transportMode, + remoteHost, + remoteRTPPort, + remoteRTCPPort, + localRTPPort); + + if (err != OK) { + looper()->unregisterHandler(mTSSender->id()); + mTSSender.clear(); + } + } + + if (err != OK) { + for (size_t i = 0; i < mTrackInfos.size(); ++i) { + TrackInfo *info = &mTrackInfos.editItemAt(i); + info->mPacketizerTrackIndex = -1; + } + + mTSPacketizer.clear(); + return err; + } + + mMode = MODE_TRANSPORT_STREAM; + mInitDoneCount = 1; + + return OK; + } + + if (mMode == MODE_TRANSPORT_STREAM) { + return INVALID_OPERATION; + } + + if ((size_t)trackIndex >= mTrackInfos.size()) { + return -ERANGE; + } + + TrackInfo *info = &mTrackInfos.editItemAt(trackIndex); + + if (info->mSender != NULL) { + return INVALID_OPERATION; + } + + sp<AMessage> notify = new AMessage(kWhatSenderNotify, id()); + notify->setInt32("generation", mGeneration); + notify->setSize("trackIndex", trackIndex); + + info->mSender = new RTPSender(mNetSession, notify); + looper()->registerHandler(info->mSender); + + status_t err = info->mSender->initAsync( + transportMode, + remoteHost, + remoteRTPPort, + remoteRTCPPort, + localRTPPort); + + if (err != OK) { + looper()->unregisterHandler(info->mSender->id()); + info->mSender.clear(); + + return err; + } + + if (mMode == MODE_UNDEFINED) { + mInitDoneCount = mTrackInfos.size(); + } + + mMode = MODE_ELEMENTARY_STREAMS; + + return OK; +} + +status_t MediaSender::queueAccessUnit( + size_t trackIndex, const sp<ABuffer> &accessUnit) { + if (mMode == MODE_UNDEFINED) { + return INVALID_OPERATION; + } + + if (trackIndex >= mTrackInfos.size()) { + return -ERANGE; + } + + if (mMode == MODE_TRANSPORT_STREAM) { + TrackInfo *info = &mTrackInfos.editItemAt(trackIndex); + info->mAccessUnits.push_back(accessUnit); + + mTSPacketizer->extractCSDIfNecessary(info->mPacketizerTrackIndex); + + for (;;) { + ssize_t minTrackIndex = -1; + int64_t minTimeUs = -1ll; + + for (size_t i = 0; i < mTrackInfos.size(); ++i) { + const TrackInfo &info = mTrackInfos.itemAt(i); + + if (info.mAccessUnits.empty()) { + minTrackIndex = -1; + minTimeUs = -1ll; + break; + } + + int64_t timeUs; + const sp<ABuffer> &accessUnit = *info.mAccessUnits.begin(); + CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs)); + + if (minTrackIndex < 0 || timeUs < minTimeUs) { + minTrackIndex = i; + minTimeUs = timeUs; + } + } + + if (minTrackIndex < 0) { + return OK; + } + + TrackInfo *info = &mTrackInfos.editItemAt(minTrackIndex); + sp<ABuffer> accessUnit = *info->mAccessUnits.begin(); + info->mAccessUnits.erase(info->mAccessUnits.begin()); + + sp<ABuffer> tsPackets; + status_t err = packetizeAccessUnit( + minTrackIndex, accessUnit, &tsPackets); + + if (err == OK) { + err = mTSSender->queueBuffer( + tsPackets, + 33 /* packetType */, + RTPSender::PACKETIZATION_TRANSPORT_STREAM); + } + + if (err != OK) { + return err; + } + } + } + + TrackInfo *info = &mTrackInfos.editItemAt(trackIndex); + + return info->mSender->queueBuffer( + accessUnit, + info->mIsAudio ? 96 : 97 /* packetType */, + info->mIsAudio + ? RTPSender::PACKETIZATION_AAC : RTPSender::PACKETIZATION_H264); +} + +void MediaSender::onMessageReceived(const sp<AMessage> &msg) { + switch (msg->what()) { + case kWhatSenderNotify: + { + int32_t generation; + CHECK(msg->findInt32("generation", &generation)); + if (generation != mGeneration) { + break; + } + + onSenderNotify(msg); + break; + } + + default: + TRESPASS(); + } +} + +void MediaSender::onSenderNotify(const sp<AMessage> &msg) { + int32_t what; + CHECK(msg->findInt32("what", &what)); + + switch (what) { + case RTPSender::kWhatInitDone: + { + --mInitDoneCount; + + int32_t err; + CHECK(msg->findInt32("err", &err)); + + if (err != OK) { + notifyInitDone(err); + ++mGeneration; + break; + } + + if (mInitDoneCount == 0) { + notifyInitDone(OK); + } + break; + } + + case RTPSender::kWhatError: + { + int32_t err; + CHECK(msg->findInt32("err", &err)); + + notifyError(err); + break; + } + + default: + TRESPASS(); + } +} + +void MediaSender::notifyInitDone(status_t err) { + sp<AMessage> notify = mNotify->dup(); + notify->setInt32("what", kWhatInitDone); + notify->setInt32("err", err); + notify->post(); +} + +void MediaSender::notifyError(status_t err) { + sp<AMessage> notify = mNotify->dup(); + notify->setInt32("what", kWhatError); + notify->setInt32("err", err); + notify->post(); +} + +status_t MediaSender::packetizeAccessUnit( + size_t trackIndex, + sp<ABuffer> accessUnit, + sp<ABuffer> *tsPackets) { + const TrackInfo &info = mTrackInfos.itemAt(trackIndex); + + uint32_t flags = 0; + + bool isHDCPEncrypted = false; + uint64_t inputCTR; + uint8_t HDCP_private_data[16]; + + bool manuallyPrependSPSPPS = + !info.mIsAudio + && (info.mFlags & FLAG_MANUALLY_PREPEND_SPS_PPS) + && IsIDR(accessUnit); + + if (mHDCP != NULL && !info.mIsAudio) { + isHDCPEncrypted = true; + + if (manuallyPrependSPSPPS) { + accessUnit = mTSPacketizer->prependCSD( + info.mPacketizerTrackIndex, accessUnit); + } + + 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; + } else if (manuallyPrependSPSPPS) { + flags |= TSPacketizer::PREPEND_SPS_PPS_TO_IDR_FRAMES; + } + + int64_t timeUs = ALooper::GetNowUs(); + if (mPrevTimeUs < 0ll || mPrevTimeUs + 100000ll <= timeUs) { + flags |= TSPacketizer::EMIT_PCR; + flags |= TSPacketizer::EMIT_PAT_AND_PMT; + + mPrevTimeUs = timeUs; + } + + mTSPacketizer->packetize( + info.mPacketizerTrackIndex, + accessUnit, + tsPackets, + flags, + !isHDCPEncrypted ? NULL : HDCP_private_data, + !isHDCPEncrypted ? 0 : sizeof(HDCP_private_data), + info.mIsAudio ? 2 : 0 /* numStuffingBytes */); + + return OK; +} + +} // namespace android + |