Commit 90a92053 authored by Andreas Huber's avatar Andreas Huber
Browse files

Various tweaks to wfd

related-to-bug: 7426218

Squashed commit of the following:

commit 1553f1a1c66af998674168f7f7a3be23fcb0c794
Author: Andreas Huber <andih@google.com>
Date:   Tue Oct 30 15:51:27 2012 -0700

    Add LPCM, AVC and AVC HRD descriptors as necessary.

    Change-Id: Ibc836fced0fe37e8a25574c2295e886765b9ea6f

commit 4e74db61d2d31ebe239acbdec8f110f88016a4ea
Author: Andreas Huber <andih@google.com>
Date:   Tue Oct 30 15:50:52 2012 -0700

    added copyright headers to Sender.{cpp,h}

    Change-Id: If615ccb8767e32bd83ed1f0f669acc39a72489f6

commit 7144bf8ae68c5cdb8faa6e219547aabbd750f04e
Author: Andreas Huber <andih@google.com>
Date:   Tue Oct 30 15:50:25 2012 -0700

    Reenable suspension of the RepeaterSource

    Change-Id: I765338fcde89c65e4b69be45a5949eba6bcdcf6f

commit 812164bcfa0699821d7d8eefcc0dff96b2e2cd08
Author: Andreas Huber <andih@google.com>
Date:   Tue Oct 30 14:03:50 2012 -0700

    Add 2 stuffing bytes to the PES headers for audio tracks.

    Change-Id: I8b9c634f6a565ab7fa7ecdb610f7d8557e0b139b

commit a084a741a63015d47c92d99fcd8b980fe615dc7d
Author: Andreas Huber <andih@google.com>
Date:   Tue Oct 30 13:19:38 2012 -0700

    Fix PCM audio packetization in WFD.

    Change-Id: I99a435f9fe6b4397f24d6c22afae5ae2505ffc14

commit c5cb9369585f701f34bce41534940d5f9b59248f
Author: Andreas Huber <andih@google.com>
Date:   Tue Oct 30 13:19:12 2012 -0700

    Support extraction of PCM audio from transport streams.

    Change-Id: I28a0516756ebcb5587325b6588df013ac871ffb9

commit b0a0512300ae037d6b39c2d04952d34b5fc12b2d
Author: Andreas Huber <andih@google.com>
Date:   Tue Oct 30 08:54:13 2012 -0700

    disable suspend of the RepeaterSource

    Change-Id: Ibf42a98185b0567f817ae582a82e6580f95d3d40

commit 4330e8b7668dc92a6d882b5622c0697cf292d04c
Author: Andreas Huber <andih@google.com>
Date:   Mon Oct 29 14:11:25 2012 -0700

    Better handling of datagrams in ANetworkSession

    reduce unnecessary copy overhead.

    Change-Id: I2ed8c767274ba07764f03e8d4913041168e5755f

commit a44e73c322ba3f2c336f7cc4e1d63d3a74faa75d
Author: Andreas Huber <andih@google.com>
Date:   Mon Oct 29 11:14:47 2012 -0700

    Network traffic is now handled on a separate thread.

    Audio and video are queued to ensure proper A/V interleaving.
    Scheduled packet sends according to capture timestamps to reduce
    send-jitter.

    Change-Id: Ibd6357c1e663086cf87bec0a98f8e54dfdfaa0e5
    related-to-bug: 7426218

Change-Id: Ia440129d656c35814abf18df06da50b73d5bb554
parent 2295ce2c
......@@ -131,6 +131,8 @@ private:
sp<AnotherPacketSource> mSource;
bool mPayloadStarted;
uint64_t mPrevPTS;
ElementaryStreamQueue *mQueue;
status_t flush();
......@@ -458,6 +460,7 @@ ATSParser::Stream::Stream(
mPCR_PID(PCR_PID),
mExpectedContinuityCounter(-1),
mPayloadStarted(false),
mPrevPTS(0),
mQueue(NULL) {
switch (mStreamType) {
case STREAMTYPE_H264:
......@@ -486,6 +489,11 @@ ATSParser::Stream::Stream(
ElementaryStreamQueue::MPEG4_VIDEO);
break;
case STREAMTYPE_PCM_AUDIO:
mQueue = new ElementaryStreamQueue(
ElementaryStreamQueue::PCM_AUDIO);
break;
default:
break;
}
......@@ -583,6 +591,7 @@ bool ATSParser::Stream::isAudio() const {
case STREAMTYPE_MPEG1_AUDIO:
case STREAMTYPE_MPEG2_AUDIO:
case STREAMTYPE_MPEG2_AUDIO_ADTS:
case STREAMTYPE_PCM_AUDIO:
return true;
default:
......@@ -827,6 +836,14 @@ status_t ATSParser::Stream::flush() {
void ATSParser::Stream::onPayloadData(
unsigned PTS_DTS_flags, uint64_t PTS, uint64_t DTS,
const uint8_t *data, size_t size) {
#if 0
ALOGI("payload streamType 0x%02x, PTS = 0x%016llx, dPTS = %lld",
mStreamType,
PTS,
(int64_t)PTS - mPrevPTS);
mPrevPTS = PTS;
#endif
ALOGV("onPayloadData mStreamType=0x%02x", mStreamType);
int64_t timeUs = 0ll; // no presentation timestamp available.
......
......@@ -87,6 +87,7 @@ struct ATSParser : public RefBase {
STREAMTYPE_MPEG2_AUDIO_ADTS = 0x0f,
STREAMTYPE_MPEG4_VIDEO = 0x10,
STREAMTYPE_H264 = 0x1b,
STREAMTYPE_PCM_AUDIO = 0x83,
};
protected:
......
......@@ -31,6 +31,8 @@
#include "include/avc_utils.h"
#include <netinet/in.h>
namespace android {
ElementaryStreamQueue::ElementaryStreamQueue(Mode mode, uint32_t flags)
......@@ -248,6 +250,11 @@ status_t ElementaryStreamQueue::appendData(
break;
}
case PCM_AUDIO:
{
break;
}
default:
TRESPASS();
break;
......@@ -324,12 +331,68 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnit() {
return dequeueAccessUnitMPEGVideo();
case MPEG4_VIDEO:
return dequeueAccessUnitMPEG4Video();
case PCM_AUDIO:
return dequeueAccessUnitPCMAudio();
default:
CHECK_EQ((unsigned)mMode, (unsigned)MPEG_AUDIO);
return dequeueAccessUnitMPEGAudio();
}
}
sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitPCMAudio() {
if (mBuffer->size() < 4) {
return NULL;
}
ABitReader bits(mBuffer->data(), 4);
CHECK_EQ(bits.getBits(8), 0xa0);
unsigned numAUs = bits.getBits(8);
bits.skipBits(8);
unsigned quantization_word_length = bits.getBits(2);
unsigned audio_sampling_frequency = bits.getBits(3);
unsigned num_channels = bits.getBits(3);
CHECK_EQ(audio_sampling_frequency, 2); // 48kHz
CHECK_EQ(num_channels, 1u); // stereo!
if (mFormat == NULL) {
mFormat = new MetaData;
mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
mFormat->setInt32(kKeyChannelCount, 2);
mFormat->setInt32(kKeySampleRate, 48000);
}
static const size_t kFramesPerAU = 80;
size_t frameSize = 2 /* numChannels */ * sizeof(int16_t);
size_t payloadSize = numAUs * frameSize * kFramesPerAU;
if (mBuffer->size() < 4 + payloadSize) {
return NULL;
}
sp<ABuffer> accessUnit = new ABuffer(payloadSize);
memcpy(accessUnit->data(), mBuffer->data() + 4, payloadSize);
int64_t timeUs = fetchTimestamp(payloadSize + 4);
CHECK_GE(timeUs, 0ll);
accessUnit->meta()->setInt64("timeUs", timeUs);
int16_t *ptr = (int16_t *)accessUnit->data();
for (size_t i = 0; i < payloadSize / sizeof(int16_t); ++i) {
ptr[i] = ntohs(ptr[i]);
}
memmove(
mBuffer->data(),
mBuffer->data() + 4 + payloadSize,
mBuffer->size() - 4 - payloadSize);
mBuffer->setRange(0, mBuffer->size() - 4 - payloadSize);
return accessUnit;
}
sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAAC() {
int64_t timeUs;
......
......@@ -35,6 +35,7 @@ struct ElementaryStreamQueue {
MPEG_AUDIO,
MPEG_VIDEO,
MPEG4_VIDEO,
PCM_AUDIO,
};
enum Flags {
......@@ -69,6 +70,7 @@ private:
sp<ABuffer> dequeueAccessUnitMPEGAudio();
sp<ABuffer> dequeueAccessUnitMPEGVideo();
sp<ABuffer> dequeueAccessUnitMPEG4Video();
sp<ABuffer> dequeueAccessUnitPCMAudio();
// consume a logical (compressed) access unit of size "size",
// returns its timestamp in us (or -1 if no time information).
......
......@@ -94,8 +94,11 @@ private:
sp<AMessage> mNotify;
bool mSawReceiveFailure, mSawSendFailure;
// for TCP / stream data
AString mOutBuffer;
List<size_t> mOutBufferSizes;
// for UDP / datagrams
List<sp<ABuffer> > mOutDatagrams;
AString mInBuffer;
......@@ -213,8 +216,8 @@ bool ANetworkSession::Session::wantsToRead() {
bool ANetworkSession::Session::wantsToWrite() {
return !mSawSendFailure
&& (mState == CONNECTING
|| ((mState == CONNECTED || mState == DATAGRAM)
&& !mOutBuffer.empty()));
|| (mState == CONNECTED && !mOutBuffer.empty())
|| (mState == DATAGRAM && !mOutDatagrams.empty()));
}
status_t ANetworkSession::Session::readMore() {
......@@ -398,30 +401,27 @@ status_t ANetworkSession::Session::readMore() {
status_t ANetworkSession::Session::writeMore() {
if (mState == DATAGRAM) {
CHECK(!mOutBufferSizes.empty());
CHECK(!mOutDatagrams.empty());
status_t err;
do {
size_t size = *mOutBufferSizes.begin();
CHECK_GE(mOutBuffer.size(), size);
const sp<ABuffer> &datagram = *mOutDatagrams.begin();
int n;
do {
n = send(mSocket, mOutBuffer.c_str(), size, 0);
n = send(mSocket, datagram->data(), datagram->size(), 0);
} while (n < 0 && errno == EINTR);
err = OK;
if (n > 0) {
mOutBufferSizes.erase(mOutBufferSizes.begin());
mOutBuffer.erase(0, n);
mOutDatagrams.erase(mOutDatagrams.begin());
} else if (n < 0) {
err = -errno;
} else if (n == 0) {
err = -ECONNRESET;
}
} while (err == OK && !mOutBufferSizes.empty());
} while (err == OK && !mOutDatagrams.empty());
if (err == -EAGAIN) {
err = OK;
......@@ -488,6 +488,16 @@ status_t ANetworkSession::Session::writeMore() {
status_t ANetworkSession::Session::sendRequest(const void *data, ssize_t size) {
CHECK(mState == CONNECTED || mState == DATAGRAM);
if (mState == DATAGRAM) {
CHECK_GE(size, 0);
sp<ABuffer> datagram = new ABuffer(size);
memcpy(datagram->data(), data, size);
mOutDatagrams.push_back(datagram);
return OK;
}
if (mState == CONNECTED && !mIsRTSPConnection) {
CHECK_LE(size, 65535);
......@@ -502,11 +512,6 @@ status_t ANetworkSession::Session::sendRequest(const void *data, ssize_t size) {
(const char *)data,
(size >= 0) ? size : strlen((const char *)data));
if (mState == DATAGRAM) {
CHECK_GE(size, 0);
mOutBufferSizes.push_back(size);
}
return OK;
}
......
......@@ -14,6 +14,7 @@ LOCAL_SRC_FILES:= \
source/MediaPuller.cpp \
source/PlaybackSession.cpp \
source/RepeaterSource.cpp \
source/Sender.cpp \
source/TSPacketizer.cpp \
source/WifiDisplaySource.cpp \
......
......@@ -465,7 +465,7 @@ status_t Converter::feedRawAudioInputBuffers() {
timeUs += copyUs;
buffer->meta()->setInt64("timeUs", timeUs);
if (copy == partialAudioAU->size() - 4) {
if (copy == partialAudioAU->capacity() - 4) {
sp<AMessage> notify = mNotify->dup();
notify->setInt32("what", kWhatAccessUnit);
notify->setBuffer("accessUnit", partialAudioAU);
......
......@@ -18,6 +18,7 @@
#define PLAYBACK_SESSION_H_
#include "Sender.h"
#include "WifiDisplaySource.h"
namespace android {
......@@ -30,10 +31,6 @@ struct MediaPuller;
struct MediaSource;
struct TSPacketizer;
#define LOG_TRANSPORT_STREAM 0
#define ENABLE_RETRANSMISSION 0
#define TRACK_BANDWIDTH 0
// Encapsulates the state of an RTP/RTCP session in the context of wifi
// display.
struct WifiDisplaySource::PlaybackSession : public AHandler {
......@@ -43,14 +40,9 @@ struct WifiDisplaySource::PlaybackSession : public AHandler {
const struct in_addr &interfaceAddr,
const sp<IHDCP> &hdcp);
enum TransportMode {
TRANSPORT_UDP,
TRANSPORT_TCP_INTERLEAVED,
TRANSPORT_TCP,
};
status_t init(
const char *clientIP, int32_t clientRtp, int32_t clientRtcp,
TransportMode transportMode,
Sender::TransportMode transportMode,
bool usePCMAudio);
void destroyAsync();
......@@ -85,29 +77,18 @@ private:
struct Track;
enum {
kWhatSendSR,
kWhatRTPNotify,
kWhatRTCPNotify,
#if ENABLE_RETRANSMISSION
kWhatRTPRetransmissionNotify,
kWhatRTCPRetransmissionNotify,
#endif
kWhatMediaPullerNotify,
kWhatConverterNotify,
kWhatTrackNotify,
kWhatSenderNotify,
kWhatUpdateSurface,
kWhatFinishPlay,
kWhatPacketize,
};
static const int64_t kSendSRIntervalUs = 10000000ll;
static const uint32_t kSourceID = 0xdeadbeef;
static const size_t kMaxHistoryLength = 128;
#if ENABLE_RETRANSMISSION
static const size_t kRetransmissionPortOffset = 120;
#endif
sp<ANetworkSession> mNetSession;
sp<Sender> mSender;
sp<ALooper> mSenderLooper;
sp<AMessage> mNotify;
in_addr mInterfaceAddr;
sp<IHDCP> mHDCP;
......@@ -121,66 +102,10 @@ private:
KeyedVector<size_t, sp<Track> > mTracks;
ssize_t mVideoTrackIndex;
sp<ABuffer> mTSQueue;
int64_t mPrevTimeUs;
TransportMode mTransportMode;
AString mClientIP;
bool mAllTracksHavePacketizerIndex;
// in TCP mode
int32_t mRTPChannel;
int32_t mRTCPChannel;
// in UDP mode
int32_t mRTPPort;
int32_t mRTPSessionID;
int32_t mRTCPSessionID;
#if ENABLE_RETRANSMISSION
int32_t mRTPRetransmissionSessionID;
int32_t mRTCPRetransmissionSessionID;
#endif
int32_t mClientRTPPort;
int32_t mClientRTCPPort;
bool mRTPConnected;
bool mRTCPConnected;
uint32_t mRTPSeqNo;
#if ENABLE_RETRANSMISSION
uint32_t mRTPRetransmissionSeqNo;
#endif
uint64_t mLastNTPTime;
uint32_t mLastRTPTime;
uint32_t mNumRTPSent;
uint32_t mNumRTPOctetsSent;
uint32_t mNumSRsSent;
bool mSendSRPending;
#if ENABLE_RETRANSMISSION
List<sp<ABuffer> > mHistory;
size_t mHistoryLength;
#endif
#if TRACK_BANDWIDTH
int64_t mFirstPacketTimeUs;
uint64_t mTotalBytesSent;
#endif
#if LOG_TRANSPORT_STREAM
FILE *mLogFile;
#endif
void onSendSR();
void addSR(const sp<ABuffer> &buffer);
void addSDES(const sp<ABuffer> &buffer);
static uint64_t GetNowNTP();
status_t setupPacketizer(bool usePCMAudio);
status_t addSource(
......@@ -196,27 +121,24 @@ private:
ssize_t appendTSData(
const void *data, size_t size, bool timeDiscontinuity, bool flush);
void scheduleSendSR();
status_t parseRTCP(const sp<ABuffer> &buffer);
#if ENABLE_RETRANSMISSION
status_t parseTSFB(const uint8_t *data, size_t size);
#endif
status_t sendPacket(int32_t sessionID, const void *data, size_t size);
status_t onFinishPlay();
status_t onFinishPlay2();
bool allTracksHavePacketizerIndex();
status_t packetizeAccessUnit(
size_t trackIndex, const sp<ABuffer> &accessUnit);
size_t trackIndex, const sp<ABuffer> &accessUnit,
sp<ABuffer> *packets);
status_t packetizeQueuedAccessUnits();
void notifySessionDead();
void drainAccessUnits();
// Returns true iff an access unit was successfully drained.
bool drainAccessUnit();
DISALLOW_EVIL_CONSTRUCTORS(PlaybackSession);
};
......
This diff is collapsed.
/*
* 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.
*/
#ifndef SENDER_H_
#define SENDER_H_
#include <media/stagefright/foundation/AHandler.h>
namespace android {
#define LOG_TRANSPORT_STREAM 0
#define ENABLE_RETRANSMISSION 0
#define TRACK_BANDWIDTH 0
struct ABuffer;
struct ANetworkSession;
struct Sender : public AHandler {
Sender(const sp<ANetworkSession> &netSession, const sp<AMessage> &notify);
enum {
kWhatInitDone,
kWhatSessionDead,
kWhatBinaryData,
};
enum TransportMode {
TRANSPORT_UDP,
TRANSPORT_TCP_INTERLEAVED,
TRANSPORT_TCP,
};
status_t init(
const char *clientIP, int32_t clientRtp, int32_t clientRtcp,
TransportMode transportMode);
status_t finishInit();
int32_t getRTPPort() const;
void queuePackets(int64_t timeUs, const sp<ABuffer> &packets);
void scheduleSendSR();
protected:
virtual ~Sender();
virtual void onMessageReceived(const sp<AMessage> &msg);
private:
enum {
kWhatQueuePackets,
kWhatSendSR,
kWhatRTPNotify,
kWhatRTCPNotify,
#if ENABLE_RETRANSMISSION
kWhatRTPRetransmissionNotify,
kWhatRTCPRetransmissionNotify
#endif
};
static const int64_t kSendSRIntervalUs = 10000000ll;
static const uint32_t kSourceID = 0xdeadbeef;
static const size_t kMaxHistoryLength = 128;
#if ENABLE_RETRANSMISSION
static const size_t kRetransmissionPortOffset = 120;
#endif
sp<ANetworkSession> mNetSession;
sp<AMessage> mNotify;
sp<ABuffer> mTSQueue;
TransportMode mTransportMode;
AString mClientIP;
// in TCP mode
int32_t mRTPChannel;
int32_t mRTCPChannel;
// in UDP mode
int32_t mRTPPort;
int32_t mRTPSessionID;
int32_t mRTCPSessionID;
#if ENABLE_RETRANSMISSION
int32_t mRTPRetransmissionSessionID;
int32_t mRTCPRetransmissionSessionID;
#endif
int32_t mClientRTPPort;
int32_t mClientRTCPPort;
bool mRTPConnected;
bool mRTCPConnected;
int64_t mFirstOutputBufferReadyTimeUs;
int64_t mFirstOutputBufferSentTimeUs;
uint32_t mRTPSeqNo;
#if ENABLE_RETRANSMISSION
uint32_t mRTPRetransmissionSeqNo;
#endif
uint64_t mLastNTPTime;
uint32_t mLastRTPTime;
uint32_t mNumRTPSent;
uint32_t mNumRTPOctetsSent;
uint32_t mNumSRsSent;
bool mSendSRPending;
#if ENABLE_RETRANSMISSION
List<sp<ABuffer> > mHistory;
size_t mHistoryLength;
#endif
#if TRACK_BANDWIDTH
int64_t mFirstPacketTimeUs;
uint64_t mTotalBytesSent;
#endif
void onSendSR();
void addSR(const sp<ABuffer> &buffer);
void addSDES(const sp<ABuffer> &buffer);
static uint64_t GetNowNTP();
#if LOG_TRANSPORT_STREAM
FILE *mLogFile;
#endif
ssize_t appendTSData(
const void *data, size_t size, bool timeDiscontinuity, bool flush);
void onQueuePackets(const sp<ABuffer> &packets);
#if ENABLE_RETRANSMISSION
status_t parseTSFB(const uint8_t *data, size_t size);
#endif
status_t parseRTCP(const sp<ABuffer> &buffer);
status_t sendPacket(int32_t sessionID, const void *data, size_t size);
void notifyInitDone();
void notifySessionDead();
DISALLOW_EVIL_CONSTRUCTORS(Sender);
};
} // namespace android
#endif // SENDER_H_
......@@ -49,10 +49,16 @@ struct TSPacketizer::Track : public RefBase {
bool isH264() const;
bool isAAC() const;
bool lacksADTSHeader() const;
bool isPCMAudio() const;
sp<ABuffer> prependCSD(const sp<ABuffer> &accessUnit) const;
sp<ABuffer> prependADTSHeader(const sp<ABuffer> &accessUnit) const;
size_t countDescriptors() const;
sp<ABuffer> descriptorAt(size_t index) const;
void finalize();
protected:
virtual ~Track();
......@@ -67,7 +73,10 @@ private:
AString mMIME;
Vector<sp<ABuffer> > mCSD;
Vector<sp<ABuffer> > mDescriptors;
bool mAudioLacksATDSHeaders;
bool mFinalized;
DISALLOW_EVIL_CONSTRUCTORS(Track);
};
......@@ -80,7 +89,8 @@ TSPacketizer::Track::Track(
mStreamType(streamType),
mStreamID(streamID),
mContinuityCounter(0),
mAudioLacksATDSHeaders(false) {
mAudioLacksATDSHeaders(false),
mFinalized(false) {
CHECK(format->findString("mime", &mMIME));
if (!strcasecmp(mMIME.c_str(), MEDIA_MIMETYPE_VIDEO_AVC)
......@@ -144,6 +154,10 @@ bool TSPacketizer::Track::isAAC() const {
return !strcasecmp(mMIME.c_str(), MEDIA_MIMETYPE_AUDIO_AAC);
}
bool TSPacketizer::Track::isPCMAudio() const {
return !strcasecmp(mMIME.c_str(), MEDIA_MIMETYPE_AUDIO_RAW);
}
bool TSPacketizer::Track::lacksADTSHeader() const {
return mAudioLacksATDSHeaders;
}
......@@ -213,6 +227,96 @@ sp<ABuffer> TSPacketizer::Track::prependADTSHeader(
return dup;
}
size_t TSPacketizer::Track::countDescriptors() const {
return mDescriptors.size();
}
sp<ABuffer> TSPacketizer::Track::descriptorAt(size_t index) const {
CHECK_LT(index, mDescriptors.size());
return mDescriptors.itemAt(index);
}
void TSPacketizer::Track::finalize() {
if (mFinalized) {
return;
}
if (isH264()) {
{
// AVC video descriptor (40)
sp<ABuffer> descriptor = new ABuffer(6);
uint8_t *data = descriptor->data();
data[0] = 40; // descriptor_tag
data[1] = 4; // descriptor_length
CHECK_EQ(mCSD.size(), 1u);
const sp<ABuffer> &sps = mCSD.itemAt(0);
CHECK(!memcmp("\x00\x00\x00\x01", sps->data(), 4));
CHECK_GE(sps->size(), 7u);
// profile_idc, constraint_set*, level_idc
memcpy(&data[2], sps->data() + 4, 3);
// AVC_still_present=0, AVC_24_hour_picture_flag=0, reserved
data[5] = 0x3f;
mDescriptors.push_back(descriptor);
}
{
// AVC timing and HRD descriptor (42)
sp<ABuffer> descriptor = new ABuffer(4);
uint8_t *data = descriptor->data();
data[0] = 42; // descriptor_tag
data[1] = 2; // descriptor_length
// hrd_management_valid_flag = 0
// reserved = 111111b
// picture_and_timing_info_present = 0
data[2] = 0x7e;
// fixed_frame_rate_flag = 0
// temporal_poc_flag = 0
// picture_to_display_conversion_flag = 0
// reserved = 11111b
data[3] = 0x1f;
mDescriptors.push_back(descriptor);
}
} else if (isPCMAudio()) {
// LPCM audio stream descriptor (0x83)
int32_t channelCount;
CHECK(mFormat->findInt32("channel-count", &channelCount));
CHECK_EQ(channelCount, 2);
int32_t sampleRate;
CHECK(mFormat->findInt32("sample-rate", &sampleRate));
CHECK(sampleRate == 44100 || sampleRate == 48000);
sp<ABuffer> descriptor = new ABuffer(4);
uint8_t *data = descriptor->data();
data[0] = 0x83; // descriptor_tag
data[1] = 2; // descriptor_length
unsigned sampling_frequency = (sampleRate == 44100) ? 1 : 2;
data[2] = (sampling_frequency << 5)
| (3 /* reserved */ << 1)
| 0 /* emphasis_flag */;
data[3] =
(1 /* number_of_channels = stereo */ << 5)
| 0xf /* reserved */;
mDescriptors.push_back(descriptor);
}
mFinalized = true;
}
////////////////////////////////////////////////////////////////////////////////
TSPacketizer::TSPacketizer()
......@@ -289,7 +393,8 @@ status_t TSPacketizer::packetize(
const sp<ABuffer> &_accessUnit,
sp<ABuffer> *packets,
uint32_t flags,
const uint8_t *PES_private_data, size_t PES_private_data_len) {
const uint8_t *PES_private_data, size_t PES_private_data_len,
size_t numStuffingBytes) {
sp<ABuffer> accessUnit = _accessUnit;
int64_t timeUs;
......@@ -347,7 +452,7 @@ status_t TSPacketizer::packetize(
// reserved = b1
// the first fragment of "buffer" follows
size_t PES_packet_length = accessUnit->size() + 8;
size_t PES_packet_length = accessUnit->size() + 8 + numStuffingBytes;
if (PES_private_data_len > 0) {
PES_packet_length += PES_private_data_len + 1;
}
......@@ -410,7 +515,7 @@ status_t TSPacketizer::packetize(
*ptr++ = 0x10 | mPATContinuityCounter;
*ptr++ = 0x00;
const uint8_t *crcDataStart = ptr;
uint8_t *crcDataStart = ptr;
*ptr++ = 0x00;
*ptr++ = 0xb0;
*ptr++ = 0x0d;
......@@ -472,8 +577,6 @@ status_t TSPacketizer::packetize(
mPMTContinuityCounter = 0;
}
size_t section_length = 5 * mTracks.size() + 4 + 9;
ptr = packetDataStart;
*ptr++ = 0x47;
*ptr++ = 0x40 | (kPID_PMT >> 8);
......@@ -483,8 +586,10 @@ status_t TSPacketizer::packetize(
crcDataStart = ptr;
*ptr++ = 0x02;
*ptr++ = 0xb0 | (section_length >> 8);
*ptr++ = section_length & 0xff;
*ptr++ = 0x00; // section_length to be filled in below.
*ptr++ = 0x00;
*ptr++ = 0x00;
*ptr++ = 0x01;
*ptr++ = 0xc3;
......@@ -498,14 +603,34 @@ status_t TSPacketizer::packetize(
for (size_t i = 0; i < mTracks.size(); ++i) {
const sp<Track> &track = mTracks.itemAt(i);
// Make sure all the decriptors have been added.
track->finalize();
*ptr++ = track->streamType();
*ptr++ = 0xe0 | (track->PID() >> 8);
*ptr++ = track->PID() & 0xff;
*ptr++ = 0xf0;
*ptr++ = 0x00;
size_t ES_info_length = 0;
for (size_t i = 0; i < track->countDescriptors(); ++i) {
ES_info_length += track->descriptorAt(i)->size();
}
CHECK_LE(ES_info_length, 0xfff);
*ptr++ = 0xf0 | (ES_info_length >> 8);
*ptr++ = (ES_info_length & 0xff);
for (size_t i = 0; i < track->countDescriptors(); ++i) {
const sp<ABuffer> &descriptor = track->descriptorAt(i);
memcpy(ptr, descriptor->data(), descriptor->size());
ptr += descriptor->size();
}
}
CHECK_EQ(ptr - crcDataStart, 12 + mTracks.size() * 5);
size_t section_length = ptr - (crcDataStart + 3) + 4 /* CRC */;
crcDataStart[1] = 0xb0 | (section_length >> 8);
crcDataStart[2] = section_length & 0xff;
crc = htonl(crc32(crcDataStart, ptr - crcDataStart));
memcpy(ptr, &crc, 4);
ptr += 4;
......@@ -601,8 +726,12 @@ status_t TSPacketizer::packetize(
*ptr++ = 0x84;
*ptr++ = (PES_private_data_len > 0) ? 0x81 : 0x80;
*ptr++ = (PES_private_data_len > 0)
? (1 + PES_private_data_len + 0x05) : 0x05;
size_t headerLength = 0x05 + numStuffingBytes;
if (PES_private_data_len > 0) {
headerLength += 1 + PES_private_data_len;
}
*ptr++ = headerLength;
*ptr++ = 0x20 | (((PTS >> 30) & 7) << 1) | 1;
*ptr++ = (PTS >> 22) & 0xff;
......@@ -616,6 +745,10 @@ status_t TSPacketizer::packetize(
ptr += PES_private_data_len;
}
for (size_t i = 0; i < numStuffingBytes; ++i) {
*ptr++ = 0xff;
}
// 18 bytes of TS/PES header leave 188 - 18 = 170 bytes for the payload
size_t sizeLeft = packetDataStart + 188 - ptr;
......
......@@ -47,7 +47,8 @@ struct TSPacketizer : public RefBase {
size_t trackIndex, const sp<ABuffer> &accessUnit,
sp<ABuffer> *packets,
uint32_t flags,
const uint8_t *PES_private_data, size_t PES_private_data_len);
const uint8_t *PES_private_data, size_t PES_private_data_len,
size_t numStuffingBytes = 0);
// XXX to be removed once encoder config option takes care of this for
// encrypted mode.
......
......@@ -22,6 +22,7 @@
#include "PlaybackSession.h"
#include "Parameters.h"
#include "ParsedMessage.h"
#include "Sender.h"
#include <binder/IServiceManager.h>
#include <gui/ISurfaceTexture.h>
......@@ -981,8 +982,7 @@ status_t WifiDisplaySource::onSetupRequest(
return ERROR_MALFORMED;
}
PlaybackSession::TransportMode transportMode =
PlaybackSession::TRANSPORT_UDP;
Sender::TransportMode transportMode = Sender::TRANSPORT_UDP;
int clientRtp, clientRtcp;
if (transport.startsWith("RTP/AVP/TCP;")) {
......@@ -991,7 +991,7 @@ status_t WifiDisplaySource::onSetupRequest(
transport.c_str(), "interleaved", &interleaved)
&& sscanf(interleaved.c_str(), "%d-%d",
&clientRtp, &clientRtcp) == 2) {
transportMode = PlaybackSession::TRANSPORT_TCP_INTERLEAVED;
transportMode = Sender::TRANSPORT_TCP_INTERLEAVED;
} else {
bool badRequest = false;
......@@ -1013,7 +1013,7 @@ status_t WifiDisplaySource::onSetupRequest(
return ERROR_MALFORMED;
}
transportMode = PlaybackSession::TRANSPORT_TCP;
transportMode = Sender::TRANSPORT_TCP;
}
} else if (transport.startsWith("RTP/AVP;unicast;")
|| transport.startsWith("RTP/AVP/UDP;unicast;")) {
......@@ -1101,7 +1101,7 @@ status_t WifiDisplaySource::onSetupRequest(
AString response = "RTSP/1.0 200 OK\r\n";
AppendCommonResponse(&response, cseq, playbackSessionID);
if (transportMode == PlaybackSession::TRANSPORT_TCP_INTERLEAVED) {
if (transportMode == Sender::TRANSPORT_TCP_INTERLEAVED) {
response.append(
StringPrintf(
"Transport: RTP/AVP/TCP;interleaved=%d-%d;",
......@@ -1110,7 +1110,7 @@ status_t WifiDisplaySource::onSetupRequest(
int32_t serverRtp = playbackSession->getRTPPort();
AString transportString = "UDP";
if (transportMode == PlaybackSession::TRANSPORT_TCP) {
if (transportMode == Sender::TRANSPORT_TCP) {
transportString = "TCP";
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment