diff options
Diffstat (limited to 'media/formats/mp2t/ts_packet.cc')
-rw-r--r-- | media/formats/mp2t/ts_packet.cc | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/media/formats/mp2t/ts_packet.cc b/media/formats/mp2t/ts_packet.cc new file mode 100644 index 0000000..8463c11 --- /dev/null +++ b/media/formats/mp2t/ts_packet.cc @@ -0,0 +1,215 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/formats/mp2t/ts_packet.h" + +#include "base/memory/scoped_ptr.h" +#include "media/base/bit_reader.h" +#include "media/formats/mp2t/mp2t_common.h" + +namespace media { +namespace mp2t { + +static const uint8 kTsHeaderSyncword = 0x47; + +// static +int TsPacket::Sync(const uint8* buf, int size) { + int k = 0; + for (; k < size; k++) { + // Verify that we have 4 syncwords in a row when possible, + // this should improve synchronization robustness. + // TODO(damienv): Consider the case where there is garbage + // between TS packets. + bool is_header = true; + for (int i = 0; i < 4; i++) { + int idx = k + i * kPacketSize; + if (idx >= size) + break; + if (buf[idx] != kTsHeaderSyncword) { + DVLOG(LOG_LEVEL_TS) + << "ByteSync" << idx << ": " + << std::hex << static_cast<int>(buf[idx]) << std::dec; + is_header = false; + break; + } + } + if (is_header) + break; + } + + DVLOG_IF(1, k != 0) << "SYNC: nbytes_skipped=" << k; + return k; +} + +// static +TsPacket* TsPacket::Parse(const uint8* buf, int size) { + if (size < kPacketSize) { + DVLOG(1) << "Buffer does not hold one full TS packet:" + << " buffer_size=" << size; + return NULL; + } + + DCHECK_EQ(buf[0], kTsHeaderSyncword); + if (buf[0] != kTsHeaderSyncword) { + DVLOG(1) << "Not on a TS syncword:" + << " buf[0]=" + << std::hex << static_cast<int>(buf[0]) << std::dec; + return NULL; + } + + scoped_ptr<TsPacket> ts_packet(new TsPacket()); + bool status = ts_packet->ParseHeader(buf); + if (!status) { + DVLOG(1) << "Parsing header failed"; + return NULL; + } + return ts_packet.release(); +} + +TsPacket::TsPacket() { +} + +TsPacket::~TsPacket() { +} + +bool TsPacket::ParseHeader(const uint8* buf) { + BitReader bit_reader(buf, kPacketSize); + payload_ = buf; + payload_size_ = kPacketSize; + + // Read the TS header: 4 bytes. + int syncword; + int transport_error_indicator; + int payload_unit_start_indicator; + int transport_priority; + int transport_scrambling_control; + int adaptation_field_control; + RCHECK(bit_reader.ReadBits(8, &syncword)); + RCHECK(bit_reader.ReadBits(1, &transport_error_indicator)); + RCHECK(bit_reader.ReadBits(1, &payload_unit_start_indicator)); + RCHECK(bit_reader.ReadBits(1, &transport_priority)); + RCHECK(bit_reader.ReadBits(13, &pid_)); + RCHECK(bit_reader.ReadBits(2, &transport_scrambling_control)); + RCHECK(bit_reader.ReadBits(2, &adaptation_field_control)); + RCHECK(bit_reader.ReadBits(4, &continuity_counter_)); + payload_unit_start_indicator_ = (payload_unit_start_indicator != 0); + payload_ += 4; + payload_size_ -= 4; + + // Default values when no adaptation field. + discontinuity_indicator_ = false; + random_access_indicator_ = false; + + // Done since no adaptation field. + if ((adaptation_field_control & 0x2) == 0) + return true; + + // Read the adaptation field if needed. + int adaptation_field_length; + RCHECK(bit_reader.ReadBits(8, &adaptation_field_length)); + DVLOG(LOG_LEVEL_TS) << "adaptation_field_length=" << adaptation_field_length; + payload_ += 1; + payload_size_ -= 1; + if ((adaptation_field_control & 0x1) == 0 && + adaptation_field_length != 183) { + DVLOG(1) << "adaptation_field_length=" << adaptation_field_length; + return false; + } + if ((adaptation_field_control & 0x1) == 1 && + adaptation_field_length > 182) { + DVLOG(1) << "adaptation_field_length=" << adaptation_field_length; + // This is not allowed by the spec. + // However, some badly encoded streams are using + // adaptation_field_length = 183 + return false; + } + + // adaptation_field_length = '0' is used to insert a single stuffing byte + // in the adaptation field of a transport stream packet. + if (adaptation_field_length == 0) + return true; + + bool status = ParseAdaptationField(&bit_reader, adaptation_field_length); + payload_ += adaptation_field_length; + payload_size_ -= adaptation_field_length; + return status; +} + +bool TsPacket::ParseAdaptationField(BitReader* bit_reader, + int adaptation_field_length) { + DCHECK_GT(adaptation_field_length, 0); + int adaptation_field_start_marker = bit_reader->bits_available() / 8; + + int discontinuity_indicator; + int random_access_indicator; + int elementary_stream_priority_indicator; + int pcr_flag; + int opcr_flag; + int splicing_point_flag; + int transport_private_data_flag; + int adaptation_field_extension_flag; + RCHECK(bit_reader->ReadBits(1, &discontinuity_indicator)); + RCHECK(bit_reader->ReadBits(1, &random_access_indicator)); + RCHECK(bit_reader->ReadBits(1, &elementary_stream_priority_indicator)); + RCHECK(bit_reader->ReadBits(1, &pcr_flag)); + RCHECK(bit_reader->ReadBits(1, &opcr_flag)); + RCHECK(bit_reader->ReadBits(1, &splicing_point_flag)); + RCHECK(bit_reader->ReadBits(1, &transport_private_data_flag)); + RCHECK(bit_reader->ReadBits(1, &adaptation_field_extension_flag)); + discontinuity_indicator_ = (discontinuity_indicator != 0); + random_access_indicator_ = (random_access_indicator != 0); + + if (pcr_flag) { + int64 program_clock_reference_base; + int reserved; + int program_clock_reference_extension; + RCHECK(bit_reader->ReadBits(33, &program_clock_reference_base)); + RCHECK(bit_reader->ReadBits(6, &reserved)); + RCHECK(bit_reader->ReadBits(9, &program_clock_reference_extension)); + } + + if (opcr_flag) { + int64 original_program_clock_reference_base; + int reserved; + int original_program_clock_reference_extension; + RCHECK(bit_reader->ReadBits(33, &original_program_clock_reference_base)); + RCHECK(bit_reader->ReadBits(6, &reserved)); + RCHECK( + bit_reader->ReadBits(9, &original_program_clock_reference_extension)); + } + + if (splicing_point_flag) { + int splice_countdown; + RCHECK(bit_reader->ReadBits(8, &splice_countdown)); + } + + if (transport_private_data_flag) { + int transport_private_data_length; + RCHECK(bit_reader->ReadBits(8, &transport_private_data_length)); + RCHECK(bit_reader->SkipBits(8 * transport_private_data_length)); + } + + if (adaptation_field_extension_flag) { + int adaptation_field_extension_length; + RCHECK(bit_reader->ReadBits(8, &adaptation_field_extension_length)); + RCHECK(bit_reader->SkipBits(8 * adaptation_field_extension_length)); + } + + // The rest of the adaptation field should be stuffing bytes. + int adaptation_field_remaining_size = adaptation_field_length - + (adaptation_field_start_marker - bit_reader->bits_available() / 8); + RCHECK(adaptation_field_remaining_size >= 0); + for (int k = 0; k < adaptation_field_remaining_size; k++) { + int stuffing_byte; + RCHECK(bit_reader->ReadBits(8, &stuffing_byte)); + RCHECK(stuffing_byte == 0xff); + } + + DVLOG(LOG_LEVEL_TS) << "random_access_indicator=" << random_access_indicator_; + return true; +} + +} // namespace mp2t +} // namespace media + |