Loading media/libstagefright/wifi-display/ANetworkSession.cpp +12 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <arpa/inet.h> #include <fcntl.h> #include <linux/tcp.h> #include <net/if.h> #include <netdb.h> #include <netinet/in.h> Loading Loading @@ -314,6 +315,9 @@ status_t ANetworkSession::Session::readMore() { sp<ABuffer> packet = new ABuffer(packetSize); memcpy(packet->data(), mInBuffer.c_str() + 2, packetSize); int64_t nowUs = ALooper::GetNowUs(); packet->meta()->setInt64("arrivalTimeUs", nowUs); sp<AMessage> notify = mNotify->dup(); notify->setInt32("sessionID", mSessionID); notify->setInt32("reason", kWhatDatagram); Loading Loading @@ -766,6 +770,14 @@ status_t ANetworkSession::createClientOrServer( res = setsockopt(s, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)); if (res < 0) { err = -errno; goto bail2; } } else if (mode == kModeCreateTCPDatagramSessionActive) { int flag = 1; res = setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)); if (res < 0) { err = -errno; goto bail2; Loading media/libstagefright/wifi-display/Android.mk +28 −4 Original line number Diff line number Diff line Loading @@ -4,21 +4,23 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ ANetworkSession.cpp \ MediaReceiver.cpp \ MediaSender.cpp \ Parameters.cpp \ ParsedMessage.cpp \ rtp/RTPAssembler.cpp \ rtp/RTPReceiver.cpp \ rtp/RTPSender.cpp \ sink/DirectRenderer.cpp \ sink/LinearRegression.cpp \ sink/RTPSink.cpp \ sink/TunnelRenderer.cpp \ sink/WifiDisplaySink.cpp \ SNTPClient.cpp \ source/Converter.cpp \ source/MediaPuller.cpp \ source/PlaybackSession.cpp \ source/RepeaterSource.cpp \ source/Sender.cpp \ source/TSPacketizer.cpp \ source/WifiDisplaySource.cpp \ TimeSeries.cpp \ VideoFormats.cpp \ LOCAL_C_INCLUDES:= \ Loading Loading @@ -85,3 +87,25 @@ LOCAL_MODULE:= udptest LOCAL_MODULE_TAGS := debug include $(BUILD_EXECUTABLE) ################################################################################ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ rtptest.cpp \ LOCAL_SHARED_LIBRARIES:= \ libbinder \ libgui \ libmedia \ libstagefright \ libstagefright_foundation \ libstagefright_wfd \ libutils \ LOCAL_MODULE:= rtptest LOCAL_MODULE_TAGS := debug include $(BUILD_EXECUTABLE) media/libstagefright/wifi-display/MediaSender.cpp 0 → 100644 +443 −0 Original line number Diff line number Diff line /* * 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 media/libstagefright/wifi-display/MediaSender.h 0 → 100644 +126 −0 Original line number Diff line number Diff line /* * 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. */ #ifndef MEDIA_SENDER_H_ #define MEDIA_SENDER_H_ #include "rtp/RTPSender.h" #include <media/stagefright/foundation/ABase.h> #include <media/stagefright/foundation/AHandler.h> #include <utils/Errors.h> #include <utils/Vector.h> namespace android { struct ABuffer; struct ANetworkSession; struct AMessage; struct IHDCP; struct TSPacketizer; // This class facilitates sending of data from one or more media tracks // through one or more RTP channels, either providing a 1:1 mapping from // track to RTP channel or muxing all tracks into a single RTP channel and // using transport stream encapsulation. // Optionally the (video) data is encrypted using the provided hdcp object. struct MediaSender : public AHandler { enum { kWhatInitDone, kWhatError, }; MediaSender( const sp<ANetworkSession> &netSession, const sp<AMessage> ¬ify); status_t setHDCP(const sp<IHDCP> &hdcp); enum FlagBits { FLAG_MANUALLY_PREPEND_SPS_PPS = 1, }; ssize_t addTrack(const sp<AMessage> &format, uint32_t flags); // If trackIndex == -1, initialize for transport stream muxing. status_t initAsync( ssize_t trackIndex, RTPSender::TransportMode transportMode, const char *remoteHost, int32_t remoteRTPPort, int32_t remoteRTCPPort, int32_t *localRTPPort); status_t queueAccessUnit( size_t trackIndex, const sp<ABuffer> &accessUnit); protected: virtual void onMessageReceived(const sp<AMessage> &msg); virtual ~MediaSender(); private: enum { kWhatSenderNotify, }; enum Mode { MODE_UNDEFINED, MODE_TRANSPORT_STREAM, MODE_ELEMENTARY_STREAMS, }; struct TrackInfo { sp<AMessage> mFormat; uint32_t mFlags; sp<RTPSender> mSender; List<sp<ABuffer> > mAccessUnits; ssize_t mPacketizerTrackIndex; bool mIsAudio; }; sp<ANetworkSession> mNetSession; sp<AMessage> mNotify; sp<IHDCP> mHDCP; Mode mMode; int32_t mGeneration; Vector<TrackInfo> mTrackInfos; sp<TSPacketizer> mTSPacketizer; sp<RTPSender> mTSSender; int64_t mPrevTimeUs; size_t mInitDoneCount; void onSenderNotify(const sp<AMessage> &msg); void notifyInitDone(status_t err); void notifyError(status_t err); status_t packetizeAccessUnit( size_t trackIndex, sp<ABuffer> accessUnit, sp<ABuffer> *tsPackets); DISALLOW_EVIL_CONSTRUCTORS(MediaSender); }; } // namespace android #endif // MEDIA_SENDER_H_ media/libstagefright/wifi-display/TimeSeries.cppdeleted 100644 → 0 +0 −67 Original line number Diff line number Diff line /* * Copyright 2012, 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. */ #include "TimeSeries.h" #include <math.h> #include <string.h> namespace android { TimeSeries::TimeSeries() : mCount(0), mSum(0.0) { } void TimeSeries::add(double val) { if (mCount < kHistorySize) { mValues[mCount++] = val; mSum += val; } else { mSum -= mValues[0]; memmove(&mValues[0], &mValues[1], (kHistorySize - 1) * sizeof(double)); mValues[kHistorySize - 1] = val; mSum += val; } } double TimeSeries::mean() const { if (mCount < 1) { return 0.0; } return mSum / mCount; } double TimeSeries::sdev() const { if (mCount < 1) { return 0.0; } double m = mean(); double sum = 0.0; for (size_t i = 0; i < mCount; ++i) { double tmp = mValues[i] - m; tmp *= tmp; sum += tmp; } return sqrt(sum / mCount); } } // namespace android Loading
media/libstagefright/wifi-display/ANetworkSession.cpp +12 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <arpa/inet.h> #include <fcntl.h> #include <linux/tcp.h> #include <net/if.h> #include <netdb.h> #include <netinet/in.h> Loading Loading @@ -314,6 +315,9 @@ status_t ANetworkSession::Session::readMore() { sp<ABuffer> packet = new ABuffer(packetSize); memcpy(packet->data(), mInBuffer.c_str() + 2, packetSize); int64_t nowUs = ALooper::GetNowUs(); packet->meta()->setInt64("arrivalTimeUs", nowUs); sp<AMessage> notify = mNotify->dup(); notify->setInt32("sessionID", mSessionID); notify->setInt32("reason", kWhatDatagram); Loading Loading @@ -766,6 +770,14 @@ status_t ANetworkSession::createClientOrServer( res = setsockopt(s, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)); if (res < 0) { err = -errno; goto bail2; } } else if (mode == kModeCreateTCPDatagramSessionActive) { int flag = 1; res = setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)); if (res < 0) { err = -errno; goto bail2; Loading
media/libstagefright/wifi-display/Android.mk +28 −4 Original line number Diff line number Diff line Loading @@ -4,21 +4,23 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ ANetworkSession.cpp \ MediaReceiver.cpp \ MediaSender.cpp \ Parameters.cpp \ ParsedMessage.cpp \ rtp/RTPAssembler.cpp \ rtp/RTPReceiver.cpp \ rtp/RTPSender.cpp \ sink/DirectRenderer.cpp \ sink/LinearRegression.cpp \ sink/RTPSink.cpp \ sink/TunnelRenderer.cpp \ sink/WifiDisplaySink.cpp \ SNTPClient.cpp \ source/Converter.cpp \ source/MediaPuller.cpp \ source/PlaybackSession.cpp \ source/RepeaterSource.cpp \ source/Sender.cpp \ source/TSPacketizer.cpp \ source/WifiDisplaySource.cpp \ TimeSeries.cpp \ VideoFormats.cpp \ LOCAL_C_INCLUDES:= \ Loading Loading @@ -85,3 +87,25 @@ LOCAL_MODULE:= udptest LOCAL_MODULE_TAGS := debug include $(BUILD_EXECUTABLE) ################################################################################ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ rtptest.cpp \ LOCAL_SHARED_LIBRARIES:= \ libbinder \ libgui \ libmedia \ libstagefright \ libstagefright_foundation \ libstagefright_wfd \ libutils \ LOCAL_MODULE:= rtptest LOCAL_MODULE_TAGS := debug include $(BUILD_EXECUTABLE)
media/libstagefright/wifi-display/MediaSender.cpp 0 → 100644 +443 −0 Original line number Diff line number Diff line /* * 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
media/libstagefright/wifi-display/MediaSender.h 0 → 100644 +126 −0 Original line number Diff line number Diff line /* * 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. */ #ifndef MEDIA_SENDER_H_ #define MEDIA_SENDER_H_ #include "rtp/RTPSender.h" #include <media/stagefright/foundation/ABase.h> #include <media/stagefright/foundation/AHandler.h> #include <utils/Errors.h> #include <utils/Vector.h> namespace android { struct ABuffer; struct ANetworkSession; struct AMessage; struct IHDCP; struct TSPacketizer; // This class facilitates sending of data from one or more media tracks // through one or more RTP channels, either providing a 1:1 mapping from // track to RTP channel or muxing all tracks into a single RTP channel and // using transport stream encapsulation. // Optionally the (video) data is encrypted using the provided hdcp object. struct MediaSender : public AHandler { enum { kWhatInitDone, kWhatError, }; MediaSender( const sp<ANetworkSession> &netSession, const sp<AMessage> ¬ify); status_t setHDCP(const sp<IHDCP> &hdcp); enum FlagBits { FLAG_MANUALLY_PREPEND_SPS_PPS = 1, }; ssize_t addTrack(const sp<AMessage> &format, uint32_t flags); // If trackIndex == -1, initialize for transport stream muxing. status_t initAsync( ssize_t trackIndex, RTPSender::TransportMode transportMode, const char *remoteHost, int32_t remoteRTPPort, int32_t remoteRTCPPort, int32_t *localRTPPort); status_t queueAccessUnit( size_t trackIndex, const sp<ABuffer> &accessUnit); protected: virtual void onMessageReceived(const sp<AMessage> &msg); virtual ~MediaSender(); private: enum { kWhatSenderNotify, }; enum Mode { MODE_UNDEFINED, MODE_TRANSPORT_STREAM, MODE_ELEMENTARY_STREAMS, }; struct TrackInfo { sp<AMessage> mFormat; uint32_t mFlags; sp<RTPSender> mSender; List<sp<ABuffer> > mAccessUnits; ssize_t mPacketizerTrackIndex; bool mIsAudio; }; sp<ANetworkSession> mNetSession; sp<AMessage> mNotify; sp<IHDCP> mHDCP; Mode mMode; int32_t mGeneration; Vector<TrackInfo> mTrackInfos; sp<TSPacketizer> mTSPacketizer; sp<RTPSender> mTSSender; int64_t mPrevTimeUs; size_t mInitDoneCount; void onSenderNotify(const sp<AMessage> &msg); void notifyInitDone(status_t err); void notifyError(status_t err); status_t packetizeAccessUnit( size_t trackIndex, sp<ABuffer> accessUnit, sp<ABuffer> *tsPackets); DISALLOW_EVIL_CONSTRUCTORS(MediaSender); }; } // namespace android #endif // MEDIA_SENDER_H_
media/libstagefright/wifi-display/TimeSeries.cppdeleted 100644 → 0 +0 −67 Original line number Diff line number Diff line /* * Copyright 2012, 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. */ #include "TimeSeries.h" #include <math.h> #include <string.h> namespace android { TimeSeries::TimeSeries() : mCount(0), mSum(0.0) { } void TimeSeries::add(double val) { if (mCount < kHistorySize) { mValues[mCount++] = val; mSum += val; } else { mSum -= mValues[0]; memmove(&mValues[0], &mValues[1], (kHistorySize - 1) * sizeof(double)); mValues[kHistorySize - 1] = val; mSum += val; } } double TimeSeries::mean() const { if (mCount < 1) { return 0.0; } return mSum / mCount; } double TimeSeries::sdev() const { if (mCount < 1) { return 0.0; } double m = mean(); double sum = 0.0; for (size_t i = 0; i < mCount; ++i) { double tmp = mValues[i] - m; tmp *= tmp; sum += tmp; } return sqrt(sum / mCount); } } // namespace android