| Index: media/mpeg2/ts_packet.cc
|
| diff --git a/media/mpeg2/ts_packet.cc b/media/mpeg2/ts_packet.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..dfde0cfe6c3e0e011763b6c4e09d6f12c748cc00
|
| --- /dev/null
|
| +++ b/media/mpeg2/ts_packet.cc
|
| @@ -0,0 +1,265 @@
|
| +// 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/mpeg2/ts_packet.h"
|
| +
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "media/base/bit_reader.h"
|
| +#include "media/mpeg2/mpeg2ts_common.h"
|
| +
|
| +namespace media {
|
| +namespace mpeg2ts {
|
| +
|
| +namespace {
|
| +
|
| +const uint8 kTsHeaderSyncword = 0x47;
|
| +
|
| +} // namespace
|
| +
|
| +// 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) {
|
| + VLOG(LOG_LEVEL_TS)
|
| + << "ByteSync" << idx << ": "
|
| + << std::hex << static_cast<int>(buf[idx]) << std::dec;
|
| + is_header = false;
|
| + break;
|
| + }
|
| + }
|
| + if (is_header) {
|
| + break;
|
| + }
|
| + }
|
| +
|
| + LOG_IF(WARNING, k != 0) << "SYNC: nbytes_skipped=" << k;
|
| + return k;
|
| +}
|
| +
|
| +// static
|
| +TsPacket* TsPacket::Parse(const uint8* buf, int size) {
|
| + if (size < kPacketSize) {
|
| + LOG(WARNING) << "Buffer does not hold one full TS packet:"
|
| + << " buffer_size=" << size;
|
| + return NULL;
|
| + }
|
| +
|
| + DCHECK_EQ(buf[0], kTsHeaderSyncword);
|
| + if (buf[0] != kTsHeaderSyncword) {
|
| + LOG(WARNING) << "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());
|
| + BitReader bit_reader(buf, kPacketSize);
|
| +
|
| + bool status = ts_packet->ParseHeader(&bit_reader);
|
| + if (!status) {
|
| + LOG(WARNING) << "Parsing header failed";
|
| + return NULL;
|
| + }
|
| +
|
| + return ts_packet.release();
|
| +}
|
| +
|
| +TsPacket::TsPacket() {
|
| +}
|
| +
|
| +TsPacket::~TsPacket() {
|
| +}
|
| +
|
| +bool TsPacket::ParseHeader(BitReader* bit_reader) {
|
| + payload_size_ = kPacketSize;
|
| +
|
| + // Read the TS header: 4 bytes.
|
| + int syncword;
|
| + DCHECK(bit_reader->ReadBits(8, &syncword));
|
| + bool transport_error_indicator;
|
| + DCHECK(bit_reader->ReadBits(1, &transport_error_indicator));
|
| + DCHECK(bit_reader->ReadBits(1, &payload_unit_start_indicator_));
|
| + bool transport_priority;
|
| + DCHECK(bit_reader->ReadBits(1, &transport_priority));
|
| + DCHECK(bit_reader->ReadBits(13, &pid_));
|
| + int transport_scrambling_control;
|
| + DCHECK(bit_reader->ReadBits(2, &transport_scrambling_control));
|
| + int adaptation_field_control;
|
| + DCHECK(bit_reader->ReadBits(2, &adaptation_field_control));
|
| + DCHECK(bit_reader->ReadBits(4, &continuity_counter_));
|
| + 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;
|
| + DCHECK(bit_reader->ReadBits(8, &adaptation_field_length));
|
| + VLOG(LOG_LEVEL_TS) << "adaptation_field_length=" << adaptation_field_length;
|
| + payload_size_ -= 1;
|
| + if ((adaptation_field_control & 0x1) == 0 &&
|
| + adaptation_field_length != 183) {
|
| + LOG(WARNING) << "adaptation_field_length=" << adaptation_field_length;
|
| + return false;
|
| + }
|
| + if ((adaptation_field_control & 0x1) == 1 &&
|
| + adaptation_field_length > 182) {
|
| + LOG(WARNING) << "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;
|
| + }
|
| +
|
| + if (adaptation_field_length == 0) {
|
| + // adaptation_field_length = '0' is for inserting a single stuffing byte
|
| + // in the adaptation field of a transport stream packet.
|
| + return true;
|
| + }
|
| +
|
| + bool status = ParseAdaptationField(bit_reader, 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);
|
| +
|
| + DCHECK(bit_reader->ReadBits(1, &discontinuity_indicator_));
|
| + DCHECK(bit_reader->ReadBits(1, &random_access_indicator_));
|
| + bool elementary_stream_priority_indicator;
|
| + DCHECK(bit_reader->ReadBits(1, &elementary_stream_priority_indicator));
|
| + bool pcr_flag;
|
| + DCHECK(bit_reader->ReadBits(1, &pcr_flag));
|
| + bool opcr_flag;
|
| + DCHECK(bit_reader->ReadBits(1, &opcr_flag));
|
| + bool splicing_point_flag;
|
| + DCHECK(bit_reader->ReadBits(1, &splicing_point_flag));
|
| + bool transport_private_data_flag;
|
| + DCHECK(bit_reader->ReadBits(1, &transport_private_data_flag));
|
| + bool adaptation_field_extension_flag;
|
| + DCHECK(bit_reader->ReadBits(1, &adaptation_field_extension_flag));
|
| + adaptation_field_length -= 1;
|
| +
|
| + if (pcr_flag) {
|
| + if (adaptation_field_length < 6) {
|
| + LOG(WARNING) << "adaptation_field_length=" << adaptation_field_length;
|
| + return false;
|
| + }
|
| + int64 program_clock_reference_base;
|
| + DCHECK(bit_reader->ReadBits(33, &program_clock_reference_base));
|
| + int reserved;
|
| + DCHECK(bit_reader->ReadBits(6, &reserved));
|
| + int program_clock_reference_extension;
|
| + DCHECK(bit_reader->ReadBits(9, &program_clock_reference_extension));
|
| + adaptation_field_length -= 6;
|
| + }
|
| +
|
| + if (opcr_flag) {
|
| + if (adaptation_field_length < 6) {
|
| + LOG(WARNING) << "adaptation_field_length=" << adaptation_field_length;
|
| + return false;
|
| + }
|
| + int64 original_program_clock_reference_base;
|
| + DCHECK(bit_reader->ReadBits(33, &original_program_clock_reference_base));
|
| + int reserved;
|
| + DCHECK(bit_reader->ReadBits(6, &reserved));
|
| + int original_program_clock_reference_extension;
|
| + DCHECK(
|
| + bit_reader->ReadBits(9, &original_program_clock_reference_extension));
|
| + adaptation_field_length -= 6;
|
| + }
|
| +
|
| + if (splicing_point_flag) {
|
| + if (adaptation_field_length < 1) {
|
| + LOG(WARNING) << "adaptation_field_length=" << adaptation_field_length;
|
| + return false;
|
| + }
|
| + int splice_countdown;
|
| + DCHECK(bit_reader->ReadBits(8, &splice_countdown));
|
| + adaptation_field_length -= 1;
|
| + }
|
| +
|
| + if (transport_private_data_flag) {
|
| + if (adaptation_field_length < 1) {
|
| + LOG(WARNING) << "adaptation_field_length=" << adaptation_field_length;
|
| + return false;
|
| + }
|
| + int transport_private_data_length;
|
| + DCHECK(bit_reader->ReadBits(8, &transport_private_data_length));
|
| + adaptation_field_length -= 1;
|
| +
|
| + if (adaptation_field_length < transport_private_data_length) {
|
| + LOG(WARNING) << "adaptation_field_length=" << adaptation_field_length
|
| + << " transport_private_data_length="
|
| + << transport_private_data_length;
|
| + return false;
|
| + }
|
| + for (int k = 0; k < transport_private_data_length; k++) {
|
| + int private_data_byte;
|
| + DCHECK(bit_reader->ReadBits(8, &private_data_byte));
|
| + }
|
| + adaptation_field_length -= transport_private_data_length;
|
| + }
|
| +
|
| + if (adaptation_field_extension_flag) {
|
| + if (adaptation_field_length < 1) {
|
| + LOG(WARNING) << "adaptation_field_length=" << adaptation_field_length;
|
| + return false;
|
| + }
|
| + int adaptation_field_extension_length;
|
| + DCHECK(bit_reader->ReadBits(8, &adaptation_field_extension_length));
|
| + adaptation_field_length -= 1;
|
| +
|
| + if (adaptation_field_length < adaptation_field_extension_length) {
|
| + LOG(WARNING) << "adaptation_field_length=" << adaptation_field_length;
|
| + return false;
|
| + }
|
| + for (int k = 0; k < adaptation_field_extension_length; k++) {
|
| + int dummy_byte;
|
| + DCHECK(bit_reader->ReadBits(8, &dummy_byte));
|
| + }
|
| + adaptation_field_length -= adaptation_field_extension_length;
|
| + }
|
| +
|
| + for (int k = 0; k < adaptation_field_length; k++) {
|
| + int stuffing_byte;
|
| + DCHECK(bit_reader->ReadBits(8, &stuffing_byte));
|
| + if (stuffing_byte != 0xff) {
|
| + LOG(WARNING) << "Invalid stuffing byte = " << stuffing_byte;
|
| + return false;
|
| + }
|
| + }
|
| +
|
| + VLOG(LOG_LEVEL_TS) << "random_access_indicator_=" << random_access_indicator_;
|
| + return true;
|
| +}
|
| +
|
| +int TsPacket::GetPayloadOffset() const {
|
| + return (kPacketSize - payload_size_);
|
| +}
|
| +
|
| +int TsPacket::GetPayloadSize() const {
|
| + return payload_size_;
|
| +}
|
| +
|
| +} // namespace mpeg2ts
|
| +} // namespace media
|
|
|