summaryrefslogtreecommitdiff
path: root/media/libstagefright/wifi-display/source/TSPacketizer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libstagefright/wifi-display/source/TSPacketizer.cpp')
-rw-r--r--media/libstagefright/wifi-display/source/TSPacketizer.cpp159
1 files changed, 146 insertions, 13 deletions
diff --git a/media/libstagefright/wifi-display/source/TSPacketizer.cpp b/media/libstagefright/wifi-display/source/TSPacketizer.cpp
index 7e660724..a5679ad9 100644
--- a/media/libstagefright/wifi-display/source/TSPacketizer.cpp
+++ b/media/libstagefright/wifi-display/source/TSPacketizer.cpp
@@ -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;