/* * 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. */ //#define LOG_NDEBUG 0 #define LOG_TAG "TSPacketizer" #include #include "TSPacketizer.h" #include "include/avc_utils.h" #include #include #include #include #include #include #include namespace android { struct TSPacketizer::Track : public RefBase { Track(const sp &format, unsigned PID, unsigned streamType, unsigned streamID); unsigned PID() const; unsigned streamType() const; unsigned streamID() const; // Returns the previous value. unsigned incrementContinuityCounter(); bool isAudio() const; bool isVideo() const; bool isH264() const; bool isAAC() const; bool lacksADTSHeader() const; bool isPCMAudio() const; sp prependCSD(const sp &accessUnit) const; sp prependADTSHeader(const sp &accessUnit) const; size_t countDescriptors() const; sp descriptorAt(size_t index) const; void finalize(); void extractCSDIfNecessary(); protected: virtual ~Track(); private: sp mFormat; unsigned mPID; unsigned mStreamType; unsigned mStreamID; unsigned mContinuityCounter; AString mMIME; Vector > mCSD; Vector > mDescriptors; bool mAudioLacksATDSHeaders; bool mFinalized; bool mExtractedCSD; DISALLOW_EVIL_CONSTRUCTORS(Track); }; TSPacketizer::Track::Track( const sp &format, unsigned PID, unsigned streamType, unsigned streamID) : mFormat(format), mPID(PID), mStreamType(streamType), mStreamID(streamID), mContinuityCounter(0), mAudioLacksATDSHeaders(false), mFinalized(false), mExtractedCSD(false) { CHECK(format->findString("mime", &mMIME)); } void TSPacketizer::Track::extractCSDIfNecessary() { if (mExtractedCSD) { return; } if (!strcasecmp(mMIME.c_str(), MEDIA_MIMETYPE_VIDEO_AVC) || !strcasecmp(mMIME.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)) { for (size_t i = 0;; ++i) { sp csd; if (!mFormat->findBuffer(AStringPrintf("csd-%d", i).c_str(), &csd)) { break; } mCSD.push(csd); } if (!strcasecmp(mMIME.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)) { int32_t isADTS; if (!mFormat->findInt32("is-adts", &isADTS) || isADTS == 0) { mAudioLacksATDSHeaders = true; } } } mExtractedCSD = true; } TSPacketizer::Track::~Track() { } unsigned TSPacketizer::Track::PID() const { return mPID; } unsigned TSPacketizer::Track::streamType() const { return mStreamType; } unsigned TSPacketizer::Track::streamID() const { return mStreamID; } unsigned TSPacketizer::Track::incrementContinuityCounter() { unsigned prevCounter = mContinuityCounter; if (++mContinuityCounter == 16) { mContinuityCounter = 0; } return prevCounter; } bool TSPacketizer::Track::isAudio() const { return !strncasecmp("audio/", mMIME.c_str(), 6); } bool TSPacketizer::Track::isVideo() const { return !strncasecmp("video/", mMIME.c_str(), 6); } bool TSPacketizer::Track::isH264() const { return !strcasecmp(mMIME.c_str(), MEDIA_MIMETYPE_VIDEO_AVC); } 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; } sp TSPacketizer::Track::prependCSD( const sp &accessUnit) const { size_t size = 0; for (size_t i = 0; i < mCSD.size(); ++i) { size += mCSD.itemAt(i)->size(); } sp dup = new ABuffer(accessUnit->size() + size); size_t offset = 0; for (size_t i = 0; i < mCSD.size(); ++i) { const sp &csd = mCSD.itemAt(i); memcpy(dup->data() + offset, csd->data(), csd->size()); offset += csd->size(); } memcpy(dup->data() + offset, accessUnit->data(), accessUnit->size()); return dup; } sp TSPacketizer::Track::prependADTSHeader( const sp &accessUnit) const { CHECK_EQ(mCSD.size(), 1u); const uint8_t *codec_specific_data = mCSD.itemAt(0)->data(); const uint32_t aac_frame_length = accessUnit->size() + 7; sp dup = new ABuffer(aac_frame_length); unsigned profile = (codec_specific_data[0] >> 3) - 1; unsigned sampling_freq_index = ((codec_specific_data[0] & 7) << 1) | (codec_specific_data[1] >> 7); unsigned channel_configuration = (codec_specific_data[1] >> 3) & 0x0f; uint8_t *ptr = dup->data(); *ptr++ = 0xff; *ptr++ = 0xf9; // b11111001, ID=1(MPEG-2), layer=0, protection_absent=1 *ptr++ = profile << 6 | sampling_freq_index << 2 | ((channel_configuration >> 2) & 1); // private_bit=0 // original_copy=0, home=0, copyright_id_bit=0, copyright_id_start=0 *ptr++ = (channel_configuration & 3) << 6 | aac_frame_length >> 11; *ptr++ = (aac_frame_length >> 3) & 0xff; *ptr++ = (aac_frame_length & 7) << 5; // adts_buffer_fullness=0, number_of_raw_data_blocks_in_frame=0 *ptr++ = 0; memcpy(ptr, accessUnit->data(), accessUnit->size()); return dup; } size_t TSPacketizer::Track::countDescriptors() const { return mDescriptors.size(); } sp 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 descriptor = new ABuffer(6); uint8_t *data = descriptor->data(); data[0] = 40; // descriptor_tag data[1] = 4; // descriptor_length if (mCSD.size() > 0) { CHECK_GE(mCSD.size(), 1u); const sp &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); } else { int32_t profileIdc, levelIdc, constraintSet; CHECK(mFormat->findInt32("profile-idc", &profileIdc)); CHECK(mFormat->findInt32("level-idc", &levelIdc)); CHECK(mFormat->findInt32("constraint-set", &constraintSet)); CHECK_GE(profileIdc, 0u); CHECK_GE(levelIdc, 0u); data[2] = profileIdc; // profile_idc data[3] = constraintSet; // constraint_set* data[4] = levelIdc; // level_idc } // 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 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 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(uint32_t flags) : mFlags(flags), mPATContinuityCounter(0), mPMTContinuityCounter(0) { initCrcTable(); if (flags & (EMIT_HDCP20_DESCRIPTOR | EMIT_HDCP21_DESCRIPTOR)) { int32_t hdcpVersion; if (flags & EMIT_HDCP20_DESCRIPTOR) { CHECK(!(flags & EMIT_HDCP21_DESCRIPTOR)); hdcpVersion = 0x20; } else { CHECK(!(flags & EMIT_HDCP20_DESCRIPTOR)); // HDCP2.0 _and_ HDCP 2.1 specs say to set the version // inside the HDCP descriptor to 0x20!!! hdcpVersion = 0x20; } // HDCP descriptor sp descriptor = new ABuffer(7); uint8_t *data = descriptor->data(); data[0] = 0x05; // descriptor_tag data[1] = 5; // descriptor_length data[2] = 'H'; data[3] = 'D'; data[4] = 'C'; data[5] = 'P'; data[6] = hdcpVersion; mProgramInfoDescriptors.push_back(descriptor); } } TSPacketizer::~TSPacketizer() { } ssize_t TSPacketizer::addTrack(const sp &format) { AString mime; CHECK(format->findString("mime", &mime)); unsigned PIDStart; bool isVideo = !strncasecmp("video/", mime.c_str(), 6); bool isAudio = !strncasecmp("audio/", mime.c_str(), 6); if (isVideo) { PIDStart = 0x1011; } else if (isAudio) { PIDStart = 0x1100; } else { return ERROR_UNSUPPORTED; } unsigned streamType; unsigned streamIDStart; unsigned streamIDStop; if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_AVC)) { streamType = 0x1b; streamIDStart = 0xe0; streamIDStop = 0xef; } else if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)) { streamType = 0x0f; streamIDStart = 0xc0; streamIDStop = 0xdf; } else if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_RAW)) { streamType = 0x83; streamIDStart = 0xbd; streamIDStop = 0xbd; } else { return ERROR_UNSUPPORTED; } size_t numTracksOfThisType = 0; unsigned PID = PIDStart; for (size_t i = 0; i < mTracks.size(); ++i) { const sp &track = mTracks.itemAt(i); if (track->streamType() == streamType) { ++numTracksOfThisType; } if ((isAudio && track->isAudio()) || (isVideo && track->isVideo())) { ++PID; } } unsigned streamID = streamIDStart + numTracksOfThisType; if (streamID > streamIDStop) { return -ERANGE; } sp track = new Track(format, PID, streamType, streamID); return mTracks.add(track); } status_t TSPacketizer::extractCSDIfNecessary(size_t trackIndex) { if (trackIndex >= mTracks.size()) { return -ERANGE; } const sp &track = mTracks.itemAt(trackIndex); track->extractCSDIfNecessary(); return OK; } status_t TSPacketizer::packetize( size_t trackIndex, const sp &_accessUnit, sp *packets, uint32_t flags, const uint8_t *PES_private_data, size_t PES_private_data_len, size_t numStuffingBytes) { sp accessUnit = _accessUnit; int64_t timeUs; CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs)); packets->clear(); if (trackIndex >= mTracks.size()) { return -ERANGE; } const sp &track = mTracks.itemAt(trackIndex); if (track->isH264() && (flags & PREPEND_SPS_PPS_TO_IDR_FRAMES) && IsIDR(accessUnit)) { // prepend codec specific data, i.e. SPS and PPS. accessUnit = track->prependCSD(accessUnit); } else if (track->isAAC() && track->lacksADTSHeader()) { CHECK(!(flags & IS_ENCRYPTED)); accessUnit = track->prependADTSHeader(accessUnit); } // 0x47 // transport_error_indicator = b0 // payload_unit_start_indicator = b1 // transport_priority = b0 // PID // transport_scrambling_control = b00 // adaptation_field_control = b?? // continuity_counter = b???? // -- payload follows // packet_startcode_prefix = 0x000001 // stream_id // PES_packet_length = 0x???? // reserved = b10 // PES_scrambling_control = b00 // PES_priority = b0 // data_alignment_indicator = b1 // copyright = b0 // original_or_copy = b0 // PTS_DTS_flags = b10 (PTS only) // ESCR_flag = b0 // ES_rate_flag = b0 // DSM_trick_mode_flag = b0 // additional_copy_info_flag = b0 // PES_CRC_flag = b0 // PES_extension_flag = b0 // PES_header_data_length = 0x05 // reserved = b0010 (PTS) // PTS[32..30] = b??? // reserved = b1 // PTS[29..15] = b??? ???? ???? ???? (15 bits) // reserved = b1 // PTS[14..0] = b??? ???? ???? ???? (15 bits) // reserved = b1 // the first fragment of "buffer" follows // Each transport packet (except for the last one contributing to the PES // payload) must contain a multiple of 16 bytes of payload per HDCP spec. bool alignPayload = (mFlags & (EMIT_HDCP20_DESCRIPTOR | EMIT_HDCP21_DESCRIPTOR)); /* a) The very first PES transport stream packet contains 4 bytes of TS header ... padding 14 bytes of static PES header PES_private_data_len + 1 bytes (only if PES_private_data_len > 0) numStuffingBytes bytes followed by the payload b) Subsequent PES transport stream packets contain 4 bytes of TS header ... padding followed by the payload */ size_t PES_packet_length = accessUnit->size() + 8 + numStuffingBytes; if (PES_private_data_len > 0) { PES_packet_length += PES_private_data_len + 1; } size_t numTSPackets = 1; { // Make sure the PES header fits into a single TS packet: size_t PES_header_size = 14 + numStuffingBytes; if (PES_private_data_len > 0) { PES_header_size += PES_private_data_len + 1; } CHECK_LE(PES_header_size, 188u - 4u); size_t sizeAvailableForPayload = 188 - 4 - PES_header_size; size_t numBytesOfPayload = accessUnit->size(); if (numBytesOfPayload > sizeAvailableForPayload) { numBytesOfPayload = sizeAvailableForPayload; if (alignPayload && numBytesOfPayload > 16) { numBytesOfPayload -= (numBytesOfPayload % 16); } } size_t numPaddingBytes = sizeAvailableForPayload - numBytesOfPayload; ALOGV("packet 1 contains %zd padding bytes and %zd bytes of payload", numPaddingBytes, numBytesOfPayload); size_t numBytesOfPayloadRemaining = accessUnit->size() - numBytesOfPayload; #if 0 // The following hopefully illustrates the logic that led to the // more efficient computation in the #else block... while (numBytesOfPayloadRemaining > 0) { size_t sizeAvailableForPayload = 188 - 4; size_t numBytesOfPayload = numBytesOfPayloadRemaining; if (numBytesOfPayload > sizeAvailableForPayload) { numBytesOfPayload = sizeAvailableForPayload; if (alignPayload && numBytesOfPayload > 16) { numBytesOfPayload -= (numBytesOfPayload % 16); } } size_t numPaddingBytes = sizeAvailableForPayload - numBytesOfPayload; ALOGI("packet %zd contains %zd padding bytes and %zd bytes of payload", numTSPackets + 1, numPaddingBytes, numBytesOfPayload); numBytesOfPayloadRemaining -= numBytesOfPayload; ++numTSPackets; } #else // This is how many bytes of payload each subsequent TS packet // can contain at most. sizeAvailableForPayload = 188 - 4; size_t sizeAvailableForAlignedPayload = sizeAvailableForPayload; if (alignPayload) { // We're only going to use a subset of the available space // since we need to make each fragment a multiple of 16 in size. sizeAvailableForAlignedPayload -= (sizeAvailableForAlignedPayload % 16); } size_t numFullTSPackets = numBytesOfPayloadRemaining / sizeAvailableForAlignedPayload; numTSPackets += numFullTSPackets; numBytesOfPayloadRemaining -= numFullTSPackets * sizeAvailableForAlignedPayload; // numBytesOfPayloadRemaining < sizeAvailableForAlignedPayload if (numFullTSPackets == 0 && numBytesOfPayloadRemaining > 0) { // There wasn't enough payload left to form a full aligned payload, // the last packet doesn't have to be aligned. ++numTSPackets; } else if (numFullTSPackets > 0 && numBytesOfPayloadRemaining + sizeAvailableForAlignedPayload > sizeAvailableForPayload) { // The last packet emitted had a full aligned payload and together // with the bytes remaining does exceed the unaligned payload // size, so we need another packet. ++numTSPackets; } #endif } if (flags & EMIT_PAT_AND_PMT) { numTSPackets += 2; } if (flags & EMIT_PCR) { ++numTSPackets; } sp buffer = new ABuffer(numTSPackets * 188); uint8_t *packetDataStart = buffer->data(); if (flags & EMIT_PAT_AND_PMT) { // Program Association Table (PAT): // 0x47 // transport_error_indicator = b0 // payload_unit_start_indicator = b1 // transport_priority = b0 // PID = b0000000000000 (13 bits) // transport_scrambling_control = b00 // adaptation_field_control = b01 (no adaptation field, payload only) // continuity_counter = b???? // skip = 0x00 // --- payload follows // table_id = 0x00 // section_syntax_indicator = b1 // must_be_zero = b0 // reserved = b11 // section_length = 0x00d // transport_stream_id = 0x0000 // reserved = b11 // version_number = b00001 // current_next_indicator = b1 // section_number = 0x00 // last_section_number = 0x00 // one program follows: // program_number = 0x0001 // reserved = b111 // program_map_PID = kPID_PMT (13 bits!) // CRC = 0x???????? if (++mPATContinuityCounter == 16) { mPATContinuityCounter = 0; } uint8_t *ptr = packetDataStart; *ptr++ = 0x47; *ptr++ = 0x40; *ptr++ = 0x00; *ptr++ = 0x10 | mPATContinuityCounter; *ptr++ = 0x00; uint8_t *crcDataStart = ptr; *ptr++ = 0x00; *ptr++ = 0xb0; *ptr++ = 0x0d; *ptr++ = 0x00; *ptr++ = 0x00; *ptr++ = 0xc3; *ptr++ = 0x00; *ptr++ = 0x00; *ptr++ = 0x00; *ptr++ = 0x01; *ptr++ = 0xe0 | (kPID_PMT >> 8); *ptr++ = kPID_PMT & 0xff; CHECK_EQ(ptr - crcDataStart, 12); uint32_t crc = htonl(crc32(crcDataStart, ptr - crcDataStart)); memcpy(ptr, &crc, 4); ptr += 4; size_t sizeLeft = packetDataStart + 188 - ptr; memset(ptr, 0xff, sizeLeft); packetDataStart += 188; // Program Map (PMT): // 0x47 // transport_error_indicator = b0 // payload_unit_start_indicator = b1 // transport_priority = b0 // PID = kPID_PMT (13 bits) // transport_scrambling_control = b00 // adaptation_field_control = b01 (no adaptation field, payload only) // continuity_counter = b???? // skip = 0x00 // -- payload follows // table_id = 0x02 // section_syntax_indicator = b1 // must_be_zero = b0 // reserved = b11 // section_length = 0x??? // program_number = 0x0001 // reserved = b11 // version_number = b00001 // current_next_indicator = b1 // section_number = 0x00 // last_section_number = 0x00 // reserved = b111 // PCR_PID = kPCR_PID (13 bits) // reserved = b1111 // program_info_length = 0x??? // program_info_descriptors follow // one or more elementary stream descriptions follow: // stream_type = 0x?? // reserved = b111 // elementary_PID = b? ???? ???? ???? (13 bits) // reserved = b1111 // ES_info_length = 0x000 // CRC = 0x???????? if (++mPMTContinuityCounter == 16) { mPMTContinuityCounter = 0; } ptr = packetDataStart; *ptr++ = 0x47; *ptr++ = 0x40 | (kPID_PMT >> 8); *ptr++ = kPID_PMT & 0xff; *ptr++ = 0x10 | mPMTContinuityCounter; *ptr++ = 0x00; crcDataStart = ptr; *ptr++ = 0x02; *ptr++ = 0x00; // section_length to be filled in below. *ptr++ = 0x00; *ptr++ = 0x00; *ptr++ = 0x01; *ptr++ = 0xc3; *ptr++ = 0x00; *ptr++ = 0x00; *ptr++ = 0xe0 | (kPID_PCR >> 8); *ptr++ = kPID_PCR & 0xff; size_t program_info_length = 0; for (size_t i = 0; i < mProgramInfoDescriptors.size(); ++i) { program_info_length += mProgramInfoDescriptors.itemAt(i)->size(); } CHECK_LT(program_info_length, 0x400); *ptr++ = 0xf0 | (program_info_length >> 8); *ptr++ = (program_info_length & 0xff); for (size_t i = 0; i < mProgramInfoDescriptors.size(); ++i) { const sp &desc = mProgramInfoDescriptors.itemAt(i); memcpy(ptr, desc->data(), desc->size()); ptr += desc->size(); } for (size_t i = 0; i < mTracks.size(); ++i) { const sp &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; 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 &descriptor = track->descriptorAt(i); memcpy(ptr, descriptor->data(), descriptor->size()); ptr += descriptor->size(); } } 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; sizeLeft = packetDataStart + 188 - ptr; memset(ptr, 0xff, sizeLeft); packetDataStart += 188; } if (flags & EMIT_PCR) { // PCR stream // 0x47 // transport_error_indicator = b0 // payload_unit_start_indicator = b1 // transport_priority = b0 // PID = kPCR_PID (13 bits) // transport_scrambling_control = b00 // adaptation_field_control = b10 (adaptation field only, no payload) // continuity_counter = b0000 (does not increment) // adaptation_field_length = 183 // discontinuity_indicator = b0 // random_access_indicator = b0 // elementary_stream_priority_indicator = b0 // PCR_flag = b1 // OPCR_flag = b0 // splicing_point_flag = b0 // transport_private_data_flag = b0 // adaptation_field_extension_flag = b0 // program_clock_reference_base = b????????????????????????????????? // reserved = b111111 // program_clock_reference_extension = b????????? int64_t nowUs = ALooper::GetNowUs(); uint64_t PCR = nowUs * 27; // PCR based on a 27MHz clock uint64_t PCR_base = PCR / 300; uint32_t PCR_ext = PCR % 300; uint8_t *ptr = packetDataStart; *ptr++ = 0x47; *ptr++ = 0x40 | (kPID_PCR >> 8); *ptr++ = kPID_PCR & 0xff; *ptr++ = 0x20; *ptr++ = 0xb7; // adaptation_field_length *ptr++ = 0x10; *ptr++ = (PCR_base >> 25) & 0xff; *ptr++ = (PCR_base >> 17) & 0xff; *ptr++ = (PCR_base >> 9) & 0xff; *ptr++ = ((PCR_base & 1) << 7) | 0x7e | ((PCR_ext >> 8) & 1); *ptr++ = (PCR_ext & 0xff); size_t sizeLeft = packetDataStart + 188 - ptr; memset(ptr, 0xff, sizeLeft); packetDataStart += 188; } uint64_t PTS = (timeUs * 9ll) / 100ll; if (PES_packet_length >= 65536) { // This really should only happen for video. CHECK(track->isVideo()); // It's valid to set this to 0 for video according to the specs. PES_packet_length = 0; } size_t sizeAvailableForPayload = 188 - 4 - 14 - numStuffingBytes; if (PES_private_data_len > 0) { sizeAvailableForPayload -= PES_private_data_len + 1; } size_t copy = accessUnit->size(); if (copy > sizeAvailableForPayload) { copy = sizeAvailableForPayload; if (alignPayload && copy > 16) { copy -= (copy % 16); } } size_t numPaddingBytes = sizeAvailableForPayload - copy; uint8_t *ptr = packetDataStart; *ptr++ = 0x47; *ptr++ = 0x40 | (track->PID() >> 8); *ptr++ = track->PID() & 0xff; *ptr++ = (numPaddingBytes > 0 ? 0x30 : 0x10) | track->incrementContinuityCounter(); if (numPaddingBytes > 0) { *ptr++ = numPaddingBytes - 1; if (numPaddingBytes >= 2) { *ptr++ = 0x00; memset(ptr, 0xff, numPaddingBytes - 2); ptr += numPaddingBytes - 2; } } *ptr++ = 0x00; *ptr++ = 0x00; *ptr++ = 0x01; *ptr++ = track->streamID(); *ptr++ = PES_packet_length >> 8; *ptr++ = PES_packet_length & 0xff; *ptr++ = 0x84; *ptr++ = (PES_private_data_len > 0) ? 0x81 : 0x80; 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; *ptr++ = (((PTS >> 15) & 0x7f) << 1) | 1; *ptr++ = (PTS >> 7) & 0xff; *ptr++ = ((PTS & 0x7f) << 1) | 1; if (PES_private_data_len > 0) { *ptr++ = 0x8e; // PES_private_data_flag, reserved. memcpy(ptr, PES_private_data, PES_private_data_len); ptr += PES_private_data_len; } for (size_t i = 0; i < numStuffingBytes; ++i) { *ptr++ = 0xff; } memcpy(ptr, accessUnit->data(), copy); ptr += copy; CHECK_EQ(ptr, packetDataStart + 188); packetDataStart += 188; size_t offset = copy; while (offset < accessUnit->size()) { // for subsequent fragments of "buffer": // 0x47 // transport_error_indicator = b0 // payload_unit_start_indicator = b0 // transport_priority = b0 // PID = b0 0001 1110 ???? (13 bits) [0x1e0 + 1 + sourceIndex] // transport_scrambling_control = b00 // adaptation_field_control = b?? // continuity_counter = b???? // the fragment of "buffer" follows. size_t sizeAvailableForPayload = 188 - 4; size_t copy = accessUnit->size() - offset; if (copy > sizeAvailableForPayload) { copy = sizeAvailableForPayload; if (alignPayload && copy > 16) { copy -= (copy % 16); } } size_t numPaddingBytes = sizeAvailableForPayload - copy; uint8_t *ptr = packetDataStart; *ptr++ = 0x47; *ptr++ = 0x00 | (track->PID() >> 8); *ptr++ = track->PID() & 0xff; *ptr++ = (numPaddingBytes > 0 ? 0x30 : 0x10) | track->incrementContinuityCounter(); if (numPaddingBytes > 0) { *ptr++ = numPaddingBytes - 1; if (numPaddingBytes >= 2) { *ptr++ = 0x00; memset(ptr, 0xff, numPaddingBytes - 2); ptr += numPaddingBytes - 2; } } memcpy(ptr, accessUnit->data() + offset, copy); ptr += copy; CHECK_EQ(ptr, packetDataStart + 188); offset += copy; packetDataStart += 188; } CHECK(packetDataStart == buffer->data() + buffer->capacity()); *packets = buffer; return OK; } void TSPacketizer::initCrcTable() { uint32_t poly = 0x04C11DB7; for (int i = 0; i < 256; i++) { uint32_t crc = i << 24; for (int j = 0; j < 8; j++) { crc = (crc << 1) ^ ((crc & 0x80000000) ? (poly) : 0); } mCrcTable[i] = crc; } } uint32_t TSPacketizer::crc32(const uint8_t *start, size_t size) const { uint32_t crc = 0xFFFFFFFF; const uint8_t *p; for (p = start; p < start + size; ++p) { crc = (crc << 8) ^ mCrcTable[((crc >> 24) ^ *p) & 0xFF]; } return crc; } sp TSPacketizer::prependCSD( size_t trackIndex, const sp &accessUnit) const { CHECK_LT(trackIndex, mTracks.size()); const sp &track = mTracks.itemAt(trackIndex); CHECK(track->isH264() && IsIDR(accessUnit)); int64_t timeUs; CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs)); sp accessUnit2 = track->prependCSD(accessUnit); accessUnit2->meta()->setInt64("timeUs", timeUs); return accessUnit2; } } // namespace android