| Index: media/mp2t/ts_packet.cc
|
| diff --git a/media/mp2t/ts_packet.cc b/media/mp2t/ts_packet.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9f02ba908d9528f250326da77c0914a46be4115d
|
| --- /dev/null
|
| +++ b/media/mp2t/ts_packet.cc
|
| @@ -0,0 +1,209 @@
|
| +// Copyright (c) 2013 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/mp2t/ts_packet.h"
|
| +
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "media/base/bit_reader.h"
|
| +#include "media/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;
|
| + bool transport_error_indicator;
|
| + bool 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_ += 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;
|
| +
|
| + bool elementary_stream_priority_indicator;
|
| + bool pcr_flag;
|
| + bool opcr_flag;
|
| + bool splicing_point_flag;
|
| + bool transport_private_data_flag;
|
| + bool 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));
|
| +
|
| + 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
|
| +
|
|
|