summaryrefslogtreecommitdiffstats
path: root/media/mp2t
diff options
context:
space:
mode:
Diffstat (limited to 'media/mp2t')
-rw-r--r--media/mp2t/es_parser.h42
-rw-r--r--media/mp2t/es_parser_adts.cc295
-rw-r--r--media/mp2t/es_parser_adts.h81
-rw-r--r--media/mp2t/es_parser_h264.cc507
-rw-r--r--media/mp2t/es_parser_h264.h97
-rw-r--r--media/mp2t/mp2t_common.h21
-rw-r--r--media/mp2t/mp2t_stream_parser.cc616
-rw-r--r--media/mp2t/mp2t_stream_parser.h133
-rw-r--r--media/mp2t/mp2t_stream_parser_unittest.cc189
-rw-r--r--media/mp2t/ts_packet.cc209
-rw-r--r--media/mp2t/ts_packet.h73
-rw-r--r--media/mp2t/ts_section.h40
-rw-r--r--media/mp2t/ts_section_pat.cc122
-rw-r--r--media/mp2t/ts_section_pat.h40
-rw-r--r--media/mp2t/ts_section_pes.cc312
-rw-r--r--media/mp2t/ts_section_pes.h64
-rw-r--r--media/mp2t/ts_section_pmt.cc122
-rw-r--r--media/mp2t/ts_section_pmt.h40
-rw-r--r--media/mp2t/ts_section_psi.cc131
-rw-r--r--media/mp2t/ts_section_psi.h54
20 files changed, 0 insertions, 3188 deletions
diff --git a/media/mp2t/es_parser.h b/media/mp2t/es_parser.h
deleted file mode 100644
index da06c5e..0000000
--- a/media/mp2t/es_parser.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 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.
-
-#ifndef MEDIA_MP2T_ES_PARSER_H_
-#define MEDIA_MP2T_ES_PARSER_H_
-
-#include "base/basictypes.h"
-#include "base/callback.h"
-#include "base/memory/ref_counted.h"
-#include "base/time/time.h"
-
-namespace media {
-
-class StreamParserBuffer;
-
-namespace mp2t {
-
-class EsParser {
- public:
- typedef base::Callback<void(scoped_refptr<StreamParserBuffer>)> EmitBufferCB;
-
- EsParser() {}
- virtual ~EsParser() {}
-
- // ES parsing.
- // Should use kNoTimestamp when a timestamp is not valid.
- virtual bool Parse(const uint8* buf, int size,
- base::TimeDelta pts,
- base::TimeDelta dts) = 0;
-
- // Flush any pending buffer.
- virtual void Flush() = 0;
-
- // Reset the state of the ES parser.
- virtual void Reset() = 0;
-};
-
-} // namespace mp2t
-} // namespace media
-
-#endif
diff --git a/media/mp2t/es_parser_adts.cc b/media/mp2t/es_parser_adts.cc
deleted file mode 100644
index b757836..0000000
--- a/media/mp2t/es_parser_adts.cc
+++ /dev/null
@@ -1,295 +0,0 @@
-// Copyright 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/es_parser_adts.h"
-
-#include <list>
-
-#include "base/basictypes.h"
-#include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
-#include "media/base/audio_timestamp_helper.h"
-#include "media/base/bit_reader.h"
-#include "media/base/buffers.h"
-#include "media/base/channel_layout.h"
-#include "media/base/stream_parser_buffer.h"
-#include "media/mp2t/mp2t_common.h"
-
-// Adts header is at least 7 bytes (can be 9 bytes).
-static const int kAdtsHeaderMinSize = 7;
-
-static const int adts_frequency_table[16] = {
- 96000,
- 88200,
- 64000,
- 48000,
- 44100,
- 32000,
- 24000,
- 22050,
- 16000,
- 12000,
- 11025,
- 8000,
- 7350,
- 0,
- 0,
- 0,
-};
-static const int kMaxSupportedFrequencyIndex = 12;
-
-static media::ChannelLayout adts_channel_layout[8] = {
- media::CHANNEL_LAYOUT_NONE,
- media::CHANNEL_LAYOUT_MONO,
- media::CHANNEL_LAYOUT_STEREO,
- media::CHANNEL_LAYOUT_SURROUND,
- media::CHANNEL_LAYOUT_4_0,
- media::CHANNEL_LAYOUT_5_0_BACK,
- media::CHANNEL_LAYOUT_5_1_BACK,
- media::CHANNEL_LAYOUT_7_1,
-};
-
-// Number of samples per frame.
-static const int kNumberSamplesPerAACFrame = 1024;
-
-static int ExtractAdtsFrameSize(const uint8* adts_header) {
- return ((static_cast<int>(adts_header[5]) >> 5) |
- (static_cast<int>(adts_header[4]) << 3) |
- ((static_cast<int>(adts_header[3]) & 0x3) << 11));
-}
-
-static int ExtractAdtsFrequencyIndex(const uint8* adts_header) {
- return ((adts_header[2] >> 2) & 0xf);
-}
-
-static int ExtractAdtsChannelConfig(const uint8* adts_header) {
- return (((adts_header[3] >> 6) & 0x3) |
- ((adts_header[2] & 0x1) << 2));
-}
-
-// Return true if buf corresponds to an ADTS syncword.
-// |buf| size must be at least 2.
-static bool isAdtsSyncWord(const uint8* buf) {
- return (buf[0] == 0xff) && ((buf[1] & 0xf6) == 0xf0);
-}
-
-// Look for an ADTS syncword.
-// |new_pos| returns
-// - either the byte position of the ADTS frame (if found)
-// - or the byte position of 1st byte that was not processed (if not found).
-// In every case, the returned value in |new_pos| is such that new_pos >= pos
-// |frame_sz| returns the size of the ADTS frame (if found).
-// Return whether a syncword was found.
-static bool LookForSyncWord(const uint8* raw_es, int raw_es_size,
- int pos,
- int* new_pos, int* frame_sz) {
- DCHECK_GE(pos, 0);
- DCHECK_LE(pos, raw_es_size);
-
- int max_offset = raw_es_size - kAdtsHeaderMinSize;
- if (pos >= max_offset) {
- // Do not change the position if:
- // - max_offset < 0: not enough bytes to get a full header
- // Since pos >= 0, this is a subcase of the next condition.
- // - pos >= max_offset: might be the case after reading one full frame,
- // |pos| is then incremented by the frame size and might then point
- // to the end of the buffer.
- *new_pos = pos;
- return false;
- }
-
- for (int offset = pos; offset < max_offset; offset++) {
- const uint8* cur_buf = &raw_es[offset];
-
- if (!isAdtsSyncWord(cur_buf))
- // The first 12 bits must be 1.
- // The layer field (2 bits) must be set to 0.
- continue;
-
- int frame_size = ExtractAdtsFrameSize(cur_buf);
- if (frame_size < kAdtsHeaderMinSize) {
- // Too short to be an ADTS frame.
- continue;
- }
-
- // Check whether there is another frame
- // |size| apart from the current one.
- int remaining_size = raw_es_size - offset;
- if (remaining_size >= frame_size + 2 &&
- !isAdtsSyncWord(&cur_buf[frame_size])) {
- continue;
- }
-
- *new_pos = offset;
- *frame_sz = frame_size;
- return true;
- }
-
- *new_pos = max_offset;
- return false;
-}
-
-namespace media {
-namespace mp2t {
-
-EsParserAdts::EsParserAdts(
- const NewAudioConfigCB& new_audio_config_cb,
- const EmitBufferCB& emit_buffer_cb)
- : new_audio_config_cb_(new_audio_config_cb),
- emit_buffer_cb_(emit_buffer_cb) {
-}
-
-EsParserAdts::~EsParserAdts() {
-}
-
-bool EsParserAdts::Parse(const uint8* buf, int size,
- base::TimeDelta pts,
- base::TimeDelta dts) {
- int raw_es_size;
- const uint8* raw_es;
-
- // The incoming PTS applies to the access unit that comes just after
- // the beginning of |buf|.
- if (pts != kNoTimestamp()) {
- es_byte_queue_.Peek(&raw_es, &raw_es_size);
- pts_list_.push_back(EsPts(raw_es_size, pts));
- }
-
- // Copy the input data to the ES buffer.
- es_byte_queue_.Push(buf, size);
- es_byte_queue_.Peek(&raw_es, &raw_es_size);
-
- // Look for every ADTS frame in the ES buffer starting at offset = 0
- int es_position = 0;
- int frame_size;
- while (LookForSyncWord(raw_es, raw_es_size, es_position,
- &es_position, &frame_size)) {
- DVLOG(LOG_LEVEL_ES)
- << "ADTS syncword @ pos=" << es_position
- << " frame_size=" << frame_size;
- DVLOG(LOG_LEVEL_ES)
- << "ADTS header: "
- << base::HexEncode(&raw_es[es_position], kAdtsHeaderMinSize);
-
- // Do not process the frame if this one is a partial frame.
- int remaining_size = raw_es_size - es_position;
- if (frame_size > remaining_size)
- break;
-
- // Update the audio configuration if needed.
- DCHECK_GE(frame_size, kAdtsHeaderMinSize);
- if (!UpdateAudioConfiguration(&raw_es[es_position]))
- return false;
-
- // Get the PTS & the duration of this access unit.
- while (!pts_list_.empty() &&
- pts_list_.front().first <= es_position) {
- audio_timestamp_helper_->SetBaseTimestamp(pts_list_.front().second);
- pts_list_.pop_front();
- }
-
- base::TimeDelta current_pts = audio_timestamp_helper_->GetTimestamp();
- base::TimeDelta frame_duration =
- audio_timestamp_helper_->GetFrameDuration(kNumberSamplesPerAACFrame);
-
- // Emit an audio frame.
- bool is_key_frame = true;
- scoped_refptr<StreamParserBuffer> stream_parser_buffer =
- StreamParserBuffer::CopyFrom(
- &raw_es[es_position],
- frame_size,
- is_key_frame);
- stream_parser_buffer->SetDecodeTimestamp(current_pts);
- stream_parser_buffer->set_timestamp(current_pts);
- stream_parser_buffer->set_duration(frame_duration);
- emit_buffer_cb_.Run(stream_parser_buffer);
-
- // Update the PTS of the next frame.
- audio_timestamp_helper_->AddFrames(kNumberSamplesPerAACFrame);
-
- // Skip the current frame.
- es_position += frame_size;
- }
-
- // Discard all the bytes that have been processed.
- DiscardEs(es_position);
-
- return true;
-}
-
-void EsParserAdts::Flush() {
-}
-
-void EsParserAdts::Reset() {
- es_byte_queue_.Reset();
- pts_list_.clear();
- last_audio_decoder_config_ = AudioDecoderConfig();
-}
-
-bool EsParserAdts::UpdateAudioConfiguration(const uint8* adts_header) {
- int frequency_index = ExtractAdtsFrequencyIndex(adts_header);
- if (frequency_index > kMaxSupportedFrequencyIndex) {
- // Frequency index 13 & 14 are reserved
- // while 15 means that the frequency is explicitly written
- // (not supported).
- return false;
- }
-
- int channel_configuration = ExtractAdtsChannelConfig(adts_header);
- if (channel_configuration == 0) {
- // TODO(damienv): Add support for inband channel configuration.
- return false;
- }
-
- // TODO(damienv): support HE-AAC frequency doubling (SBR)
- // based on the incoming ADTS profile.
- int samples_per_second = adts_frequency_table[frequency_index];
- int adts_profile = (adts_header[2] >> 6) & 0x3;
-
- AudioDecoderConfig audio_decoder_config(
- kCodecAAC,
- kSampleFormatS16,
- adts_channel_layout[channel_configuration],
- samples_per_second,
- NULL, 0,
- false);
-
- if (!audio_decoder_config.Matches(last_audio_decoder_config_)) {
- DVLOG(1) << "Sampling frequency: " << samples_per_second;
- DVLOG(1) << "Channel config: " << channel_configuration;
- DVLOG(1) << "Adts profile: " << adts_profile;
- // Reset the timestamp helper to use a new time scale.
- if (audio_timestamp_helper_) {
- base::TimeDelta base_timestamp = audio_timestamp_helper_->GetTimestamp();
- audio_timestamp_helper_.reset(
- new AudioTimestampHelper(samples_per_second));
- audio_timestamp_helper_->SetBaseTimestamp(base_timestamp);
- } else {
- audio_timestamp_helper_.reset(
- new AudioTimestampHelper(samples_per_second));
- }
- // Audio config notification.
- last_audio_decoder_config_ = audio_decoder_config;
- new_audio_config_cb_.Run(audio_decoder_config);
- }
-
- return true;
-}
-
-void EsParserAdts::DiscardEs(int nbytes) {
- DCHECK_GE(nbytes, 0);
- if (nbytes <= 0)
- return;
-
- // Adjust the ES position of each PTS.
- for (EsPtsList::iterator it = pts_list_.begin(); it != pts_list_.end(); ++it)
- it->first -= nbytes;
-
- // Discard |nbytes| of ES.
- es_byte_queue_.Pop(nbytes);
-}
-
-} // namespace mp2t
-} // namespace media
-
diff --git a/media/mp2t/es_parser_adts.h b/media/mp2t/es_parser_adts.h
deleted file mode 100644
index fd0fe58..0000000
--- a/media/mp2t/es_parser_adts.h
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 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.
-
-#ifndef MEDIA_MP2T_ES_PARSER_ADTS_H_
-#define MEDIA_MP2T_ES_PARSER_ADTS_H_
-
-#include <list>
-#include <utility>
-
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/time/time.h"
-#include "media/base/audio_decoder_config.h"
-#include "media/base/byte_queue.h"
-#include "media/mp2t/es_parser.h"
-
-namespace media {
-class AudioTimestampHelper;
-class BitReader;
-class StreamParserBuffer;
-}
-
-namespace media {
-namespace mp2t {
-
-class EsParserAdts : public EsParser {
- public:
- typedef base::Callback<void(const AudioDecoderConfig&)> NewAudioConfigCB;
-
- EsParserAdts(const NewAudioConfigCB& new_audio_config_cb,
- const EmitBufferCB& emit_buffer_cb);
- virtual ~EsParserAdts();
-
- // EsParser implementation.
- virtual bool Parse(const uint8* buf, int size,
- base::TimeDelta pts,
- base::TimeDelta dts) OVERRIDE;
- virtual void Flush() OVERRIDE;
- virtual void Reset() OVERRIDE;
-
- private:
- // Used to link a PTS with a byte position in the ES stream.
- typedef std::pair<int, base::TimeDelta> EsPts;
- typedef std::list<EsPts> EsPtsList;
-
- // Signal any audio configuration change (if any).
- // Return false if the current audio config is not
- // a supported ADTS audio config.
- bool UpdateAudioConfiguration(const uint8* adts_header);
-
- // Discard some bytes from the ES stream.
- void DiscardEs(int nbytes);
-
- // Callbacks:
- // - to signal a new audio configuration,
- // - to send ES buffers.
- NewAudioConfigCB new_audio_config_cb_;
- EmitBufferCB emit_buffer_cb_;
-
- // Bytes of the ES stream that have not been emitted yet.
- ByteQueue es_byte_queue_;
-
- // List of PTS associated with a position in the ES stream.
- EsPtsList pts_list_;
-
- // Interpolated PTS for frames that don't have one.
- scoped_ptr<AudioTimestampHelper> audio_timestamp_helper_;
-
- // Last audio config.
- AudioDecoderConfig last_audio_decoder_config_;
-
- DISALLOW_COPY_AND_ASSIGN(EsParserAdts);
-};
-
-} // namespace mp2t
-} // namespace media
-
-#endif
-
diff --git a/media/mp2t/es_parser_h264.cc b/media/mp2t/es_parser_h264.cc
deleted file mode 100644
index 8a9b415..0000000
--- a/media/mp2t/es_parser_h264.cc
+++ /dev/null
@@ -1,507 +0,0 @@
-// Copyright 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/es_parser_h264.h"
-
-#include "base/basictypes.h"
-#include "base/logging.h"
-#include "media/base/bit_reader.h"
-#include "media/base/buffers.h"
-#include "media/base/stream_parser_buffer.h"
-#include "media/base/video_frame.h"
-#include "media/mp2t/mp2t_common.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/size.h"
-
-static const int kExtendedSar = 255;
-
-// ISO 14496 part 10
-// VUI parameters: Table E-1 "Meaning of sample aspect ratio indicator"
-static const int kTableSarWidth[14] = {
- 1, 1, 12, 10, 16, 40, 24, 20, 32, 80, 18, 15, 64, 160
-};
-
-static const int kTableSarHeight[14] = {
- 1, 1, 11, 11, 11, 33, 11, 11, 11, 33, 11, 11, 33, 99
-};
-
-// Remove the start code emulation prevention ( 0x000003 )
-// and return the size of the converted buffer.
-// Note: Size of |buf_rbsp| should be at least |size| to accomodate
-// the worst case.
-static int ConvertToRbsp(const uint8* buf, int size, uint8* buf_rbsp) {
- int rbsp_size = 0;
- int zero_count = 0;
- for (int k = 0; k < size; k++) {
- if (buf[k] == 0x3 && zero_count >= 2) {
- zero_count = 0;
- continue;
- }
- if (buf[k] == 0)
- zero_count++;
- else
- zero_count = 0;
- buf_rbsp[rbsp_size++] = buf[k];
- }
- return rbsp_size;
-}
-
-namespace media {
-namespace mp2t {
-
-// ISO 14496 - Part 10: Table 7-1 "NAL unit type codes"
-enum NalUnitType {
- kNalUnitTypeNonIdrSlice = 1,
- kNalUnitTypeIdrSlice = 5,
- kNalUnitTypeSPS = 7,
- kNalUnitTypePPS = 8,
- kNalUnitTypeAUD = 9,
-};
-
-class BitReaderH264 : public BitReader {
- public:
- BitReaderH264(const uint8* data, off_t size)
- : BitReader(data, size) { }
-
- // Read an unsigned exp-golomb value.
- // Return true if successful.
- bool ReadBitsExpGolomb(uint32* exp_golomb_value);
-};
-
-bool BitReaderH264::ReadBitsExpGolomb(uint32* exp_golomb_value) {
- // Get the number of leading zeros.
- int zero_count = 0;
- while (true) {
- int one_bit;
- RCHECK(ReadBits(1, &one_bit));
- if (one_bit != 0)
- break;
- zero_count++;
- }
-
- // If zero_count is greater than 31, the calculated value will overflow.
- if (zero_count > 31) {
- SkipBits(zero_count);
- return false;
- }
-
- // Read the actual value.
- uint32 base = (1 << zero_count) - 1;
- uint32 offset;
- RCHECK(ReadBits(zero_count, &offset));
- *exp_golomb_value = base + offset;
-
- return true;
-}
-
-EsParserH264::EsParserH264(
- const NewVideoConfigCB& new_video_config_cb,
- const EmitBufferCB& emit_buffer_cb)
- : new_video_config_cb_(new_video_config_cb),
- emit_buffer_cb_(emit_buffer_cb),
- es_pos_(0),
- current_nal_pos_(-1),
- current_access_unit_pos_(-1),
- is_key_frame_(false) {
-}
-
-EsParserH264::~EsParserH264() {
-}
-
-bool EsParserH264::Parse(const uint8* buf, int size,
- base::TimeDelta pts,
- base::TimeDelta dts) {
- // Note: Parse is invoked each time a PES packet has been reassembled.
- // Unfortunately, a PES packet does not necessarily map
- // to an h264 access unit, although the HLS recommendation is to use one PES
- // for each access unit (but this is just a recommendation and some streams
- // do not comply with this recommendation).
-
- // Link position |raw_es_size| in the ES stream with a timing descriptor.
- // HLS recommendation: "In AVC video, you should have both a DTS and a
- // PTS in each PES header".
- if (dts == kNoTimestamp() && pts == kNoTimestamp()) {
- DVLOG(1) << "A timestamp must be provided for each reassembled PES";
- return false;
- }
- TimingDesc timing_desc;
- timing_desc.pts = pts;
- timing_desc.dts = (dts != kNoTimestamp()) ? dts : pts;
-
- int raw_es_size;
- const uint8* raw_es;
- es_byte_queue_.Peek(&raw_es, &raw_es_size);
- timing_desc_list_.push_back(
- std::pair<int, TimingDesc>(raw_es_size, timing_desc));
-
- // Add the incoming bytes to the ES queue.
- es_byte_queue_.Push(buf, size);
-
- // Add NALs from the incoming buffer.
- if (!ParseInternal())
- return false;
-
- // Discard emitted frames
- // or every byte that was parsed so far if there is no current frame.
- int skip_count =
- (current_access_unit_pos_ >= 0) ? current_access_unit_pos_ : es_pos_;
- DiscardEs(skip_count);
-
- return true;
-}
-
-void EsParserH264::Flush() {
- if (current_access_unit_pos_ < 0)
- return;
-
- // Force emitting the last access unit.
- int next_aud_pos;
- const uint8* raw_es;
- es_byte_queue_.Peek(&raw_es, &next_aud_pos);
- EmitFrameIfNeeded(next_aud_pos);
- current_nal_pos_ = -1;
- StartFrame(-1);
-
- // Discard the emitted frame.
- DiscardEs(next_aud_pos);
-}
-
-void EsParserH264::Reset() {
- DVLOG(1) << "EsParserH264::Reset";
- es_byte_queue_.Reset();
- timing_desc_list_.clear();
- es_pos_ = 0;
- current_nal_pos_ = -1;
- StartFrame(-1);
- last_video_decoder_config_ = VideoDecoderConfig();
-}
-
-bool EsParserH264::ParseInternal() {
- int raw_es_size;
- const uint8* raw_es;
- es_byte_queue_.Peek(&raw_es, &raw_es_size);
-
- DCHECK_GE(es_pos_, 0);
- DCHECK_LT(es_pos_, raw_es_size);
-
- // Resume h264 es parsing where it was left.
- for ( ; es_pos_ < raw_es_size - 4; es_pos_++) {
- // Make sure the syncword is either 00 00 00 01 or 00 00 01
- if (raw_es[es_pos_ + 0] != 0 || raw_es[es_pos_ + 1] != 0)
- continue;
- int syncword_length = 0;
- if (raw_es[es_pos_ + 2] == 0 && raw_es[es_pos_ + 3] == 1)
- syncword_length = 4;
- else if (raw_es[es_pos_ + 2] == 1)
- syncword_length = 3;
- else
- continue;
-
- // Parse the current NAL (and the new NAL then becomes the current one).
- if (current_nal_pos_ >= 0) {
- int nal_size = es_pos_ - current_nal_pos_;
- DCHECK_GT(nal_size, 0);
- RCHECK(NalParser(&raw_es[current_nal_pos_], nal_size));
- }
- current_nal_pos_ = es_pos_ + syncword_length;
-
- // Retrieve the NAL type.
- int nal_header = raw_es[current_nal_pos_];
- int forbidden_zero_bit = (nal_header >> 7) & 0x1;
- RCHECK(forbidden_zero_bit == 0);
- NalUnitType nal_unit_type = static_cast<NalUnitType>(nal_header & 0x1f);
- DVLOG(LOG_LEVEL_ES) << "nal: offset=" << es_pos_
- << " type=" << nal_unit_type;
-
- // Emit a frame if needed.
- if (nal_unit_type == kNalUnitTypeAUD)
- EmitFrameIfNeeded(es_pos_);
-
- // Skip the syncword.
- es_pos_ += syncword_length;
- }
-
- return true;
-}
-
-void EsParserH264::EmitFrameIfNeeded(int next_aud_pos) {
- // There is no current frame: start a new frame.
- if (current_access_unit_pos_ < 0) {
- StartFrame(next_aud_pos);
- return;
- }
-
- // Get the access unit timing info.
- TimingDesc current_timing_desc;
- while (!timing_desc_list_.empty() &&
- timing_desc_list_.front().first <= current_access_unit_pos_) {
- current_timing_desc = timing_desc_list_.front().second;
- timing_desc_list_.pop_front();
- }
-
- // Emit a frame.
- int raw_es_size;
- const uint8* raw_es;
- es_byte_queue_.Peek(&raw_es, &raw_es_size);
- int access_unit_size = next_aud_pos - current_access_unit_pos_;
- scoped_refptr<StreamParserBuffer> stream_parser_buffer =
- StreamParserBuffer::CopyFrom(
- &raw_es[current_access_unit_pos_],
- access_unit_size,
- is_key_frame_);
- stream_parser_buffer->SetDecodeTimestamp(current_timing_desc.dts);
- stream_parser_buffer->set_timestamp(current_timing_desc.pts);
- emit_buffer_cb_.Run(stream_parser_buffer);
-
- // Set the current frame position to the next AUD position.
- StartFrame(next_aud_pos);
-}
-
-void EsParserH264::StartFrame(int aud_pos) {
- // Two cases:
- // - if aud_pos < 0, clear the current frame and set |is_key_frame| to a
- // default value (false).
- // - if aud_pos >= 0, start a new frame and set |is_key_frame| to true
- // |is_key_frame_| will be updated while parsing the NALs of that frame.
- // If any NAL is a non IDR NAL, it will be set to false.
- current_access_unit_pos_ = aud_pos;
- is_key_frame_ = (aud_pos >= 0);
-}
-
-void EsParserH264::DiscardEs(int nbytes) {
- DCHECK_GE(nbytes, 0);
- if (nbytes == 0)
- return;
-
- // Update the position of
- // - the parser,
- // - the current NAL,
- // - the current access unit.
- es_pos_ -= nbytes;
- if (es_pos_ < 0)
- es_pos_ = 0;
-
- if (current_nal_pos_ >= 0) {
- DCHECK_GE(current_nal_pos_, nbytes);
- current_nal_pos_ -= nbytes;
- }
- if (current_access_unit_pos_ >= 0) {
- DCHECK_GE(current_access_unit_pos_, nbytes);
- current_access_unit_pos_ -= nbytes;
- }
-
- // Update the timing information accordingly.
- std::list<std::pair<int, TimingDesc> >::iterator timing_it
- = timing_desc_list_.begin();
- for (; timing_it != timing_desc_list_.end(); ++timing_it)
- timing_it->first -= nbytes;
-
- // Discard |nbytes| of ES.
- es_byte_queue_.Pop(nbytes);
-}
-
-bool EsParserH264::NalParser(const uint8* buf, int size) {
- // Get the NAL header.
- if (size < 1) {
- DVLOG(1) << "NalParser: incomplete NAL";
- return false;
- }
- int nal_header = buf[0];
- buf += 1;
- size -= 1;
-
- int forbidden_zero_bit = (nal_header >> 7) & 0x1;
- if (forbidden_zero_bit != 0)
- return false;
- int nal_ref_idc = (nal_header >> 5) & 0x3;
- int nal_unit_type = nal_header & 0x1f;
-
- // Process the NAL content.
- switch (nal_unit_type) {
- case kNalUnitTypeSPS:
- DVLOG(LOG_LEVEL_ES) << "NAL: SPS";
- // |nal_ref_idc| should not be 0 for a SPS.
- if (nal_ref_idc == 0)
- return false;
- return ProcessSPS(buf, size);
- case kNalUnitTypeIdrSlice:
- DVLOG(LOG_LEVEL_ES) << "NAL: IDR slice";
- return true;
- case kNalUnitTypeNonIdrSlice:
- DVLOG(LOG_LEVEL_ES) << "NAL: Non IDR slice";
- is_key_frame_ = false;
- return true;
- case kNalUnitTypePPS:
- DVLOG(LOG_LEVEL_ES) << "NAL: PPS";
- return true;
- case kNalUnitTypeAUD:
- DVLOG(LOG_LEVEL_ES) << "NAL: AUD";
- return true;
- default:
- DVLOG(LOG_LEVEL_ES) << "NAL: " << nal_unit_type;
- return true;
- }
-
- NOTREACHED();
- return false;
-}
-
-bool EsParserH264::ProcessSPS(const uint8* buf, int size) {
- if (size <= 0)
- return false;
-
- // Removes start code emulation prevention.
- // TODO(damienv): refactoring in media/base
- // so as to have a unique H264 bit reader in Chrome.
- scoped_ptr<uint8[]> buf_rbsp(new uint8[size]);
- int rbsp_size = ConvertToRbsp(buf, size, buf_rbsp.get());
-
- BitReaderH264 bit_reader(buf_rbsp.get(), rbsp_size);
-
- int profile_idc;
- int constraint_setX_flag;
- int level_idc;
- uint32 seq_parameter_set_id;
- uint32 log2_max_frame_num_minus4;
- uint32 pic_order_cnt_type;
- RCHECK(bit_reader.ReadBits(8, &profile_idc));
- RCHECK(bit_reader.ReadBits(8, &constraint_setX_flag));
- RCHECK(bit_reader.ReadBits(8, &level_idc));
- RCHECK(bit_reader.ReadBitsExpGolomb(&seq_parameter_set_id));
- RCHECK(bit_reader.ReadBitsExpGolomb(&log2_max_frame_num_minus4));
- RCHECK(bit_reader.ReadBitsExpGolomb(&pic_order_cnt_type));
-
- // |pic_order_cnt_type| shall be in the range of 0 to 2.
- RCHECK(pic_order_cnt_type <= 2);
- if (pic_order_cnt_type == 0) {
- uint32 log2_max_pic_order_cnt_lsb_minus4;
- RCHECK(bit_reader.ReadBitsExpGolomb(&log2_max_pic_order_cnt_lsb_minus4));
- } else if (pic_order_cnt_type == 1) {
- // Note: |offset_for_non_ref_pic| and |offset_for_top_to_bottom_field|
- // corresponds to their codenum not to their actual value.
- bool delta_pic_order_always_zero_flag;
- uint32 offset_for_non_ref_pic;
- uint32 offset_for_top_to_bottom_field;
- uint32 num_ref_frames_in_pic_order_cnt_cycle;
- RCHECK(bit_reader.ReadBits(1, &delta_pic_order_always_zero_flag));
- RCHECK(bit_reader.ReadBitsExpGolomb(&offset_for_non_ref_pic));
- RCHECK(bit_reader.ReadBitsExpGolomb(&offset_for_top_to_bottom_field));
- RCHECK(
- bit_reader.ReadBitsExpGolomb(&num_ref_frames_in_pic_order_cnt_cycle));
- for (uint32 i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++) {
- uint32 offset_for_ref_frame_codenum;
- RCHECK(bit_reader.ReadBitsExpGolomb(&offset_for_ref_frame_codenum));
- }
- }
-
- uint32 num_ref_frames;
- int gaps_in_frame_num_value_allowed_flag;
- uint32 pic_width_in_mbs_minus1;
- uint32 pic_height_in_map_units_minus1;
- RCHECK(bit_reader.ReadBitsExpGolomb(&num_ref_frames));
- RCHECK(bit_reader.ReadBits(1, &gaps_in_frame_num_value_allowed_flag));
- RCHECK(bit_reader.ReadBitsExpGolomb(&pic_width_in_mbs_minus1));
- RCHECK(bit_reader.ReadBitsExpGolomb(&pic_height_in_map_units_minus1));
-
- int frame_mbs_only_flag;
- RCHECK(bit_reader.ReadBits(1, &frame_mbs_only_flag));
- if (!frame_mbs_only_flag) {
- int mb_adaptive_frame_field_flag;
- RCHECK(bit_reader.ReadBits(1, &mb_adaptive_frame_field_flag));
- }
-
- int direct_8x8_inference_flag;
- RCHECK(bit_reader.ReadBits(1, &direct_8x8_inference_flag));
-
- bool frame_cropping_flag;
- uint32 frame_crop_left_offset = 0;
- uint32 frame_crop_right_offset = 0;
- uint32 frame_crop_top_offset = 0;
- uint32 frame_crop_bottom_offset = 0;
- RCHECK(bit_reader.ReadBits(1, &frame_cropping_flag));
- if (frame_cropping_flag) {
- RCHECK(bit_reader.ReadBitsExpGolomb(&frame_crop_left_offset));
- RCHECK(bit_reader.ReadBitsExpGolomb(&frame_crop_right_offset));
- RCHECK(bit_reader.ReadBitsExpGolomb(&frame_crop_top_offset));
- RCHECK(bit_reader.ReadBitsExpGolomb(&frame_crop_bottom_offset));
- }
-
- bool vui_parameters_present_flag;
- RCHECK(bit_reader.ReadBits(1, &vui_parameters_present_flag));
- int sar_width = 1;
- int sar_height = 1;
- if (vui_parameters_present_flag) {
- // Read only the aspect ratio information from the VUI section.
- // TODO(damienv): check whether other VUI info are useful.
- bool aspect_ratio_info_present_flag = false;
- RCHECK(bit_reader.ReadBits(1, &aspect_ratio_info_present_flag));
- if (aspect_ratio_info_present_flag) {
- int aspect_ratio_idc;
- RCHECK(bit_reader.ReadBits(8, &aspect_ratio_idc));
- if (aspect_ratio_idc == kExtendedSar) {
- RCHECK(bit_reader.ReadBits(16, &sar_width));
- RCHECK(bit_reader.ReadBits(16, &sar_height));
- } else if (aspect_ratio_idc < 14) {
- sar_width = kTableSarWidth[aspect_ratio_idc];
- sar_height = kTableSarHeight[aspect_ratio_idc];
- }
- }
- }
-
- if (sar_width != sar_height) {
- // TODO(damienv): Support non square pixels.
- DVLOG(1)
- << "Non square pixel not supported yet:"
- << " sar_width=" << sar_width
- << " sar_height=" << sar_height;
- return false;
- }
-
- // TODO(damienv): a MAP unit can be either 16 or 32 pixels.
- // although it's 16 pixels for progressive non MBAFF frames.
- gfx::Size coded_size((pic_width_in_mbs_minus1 + 1) * 16,
- (pic_height_in_map_units_minus1 + 1) * 16);
- gfx::Rect visible_rect(
- frame_crop_left_offset,
- frame_crop_top_offset,
- (coded_size.width() - frame_crop_right_offset) - frame_crop_left_offset,
- (coded_size.height() - frame_crop_bottom_offset) - frame_crop_top_offset);
-
- // TODO(damienv): calculate the natural size based
- // on the possible aspect ratio coded in the VUI parameters.
- gfx::Size natural_size(visible_rect.width(),
- visible_rect.height());
-
- // TODO(damienv):
- // Assuming the SPS is used right away by the PPS
- // and the slice headers is a strong assumption.
- // In theory, we should process the SPS and PPS
- // and only when one of the slice header is switching
- // the PPS id, the video decoder config should be changed.
- VideoDecoderConfig video_decoder_config(
- kCodecH264,
- VIDEO_CODEC_PROFILE_UNKNOWN, // TODO(damienv)
- VideoFrame::YV12,
- coded_size,
- visible_rect,
- natural_size,
- NULL, 0,
- false);
-
- if (!video_decoder_config.Matches(last_video_decoder_config_)) {
- DVLOG(1) << "Profile IDC: " << profile_idc;
- DVLOG(1) << "Level IDC: " << level_idc;
- DVLOG(1) << "Pic width: " << (pic_width_in_mbs_minus1 + 1) * 16;
- DVLOG(1) << "Pic height: " << (pic_height_in_map_units_minus1 + 1) * 16;
- DVLOG(1) << "log2_max_frame_num_minus4: " << log2_max_frame_num_minus4;
- last_video_decoder_config_ = video_decoder_config;
- new_video_config_cb_.Run(video_decoder_config);
- }
-
- return true;
-}
-
-} // namespace mp2t
-} // namespace media
-
diff --git a/media/mp2t/es_parser_h264.h b/media/mp2t/es_parser_h264.h
deleted file mode 100644
index 5cb247e..0000000
--- a/media/mp2t/es_parser_h264.h
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 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.
-
-#ifndef MEDIA_MP2T_ES_PARSER_H264_H_
-#define MEDIA_MP2T_ES_PARSER_H264_H_
-
-#include <list>
-#include <utility>
-
-#include "base/basictypes.h"
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "base/time/time.h"
-#include "media/base/byte_queue.h"
-#include "media/base/video_decoder_config.h"
-#include "media/mp2t/es_parser.h"
-
-namespace media {
-class BitReader;
-class StreamParserBuffer;
-}
-
-namespace media {
-namespace mp2t {
-
-// Remark:
-// In this h264 parser, frame splitting is based on AUD nals.
-// Mpeg2 TS spec: "2.14 Carriage of Rec. ITU-T H.264 | ISO/IEC 14496-10 video"
-// "Each AVC access unit shall contain an access unit delimiter NAL Unit;"
-//
-class EsParserH264 : public EsParser {
- public:
- typedef base::Callback<void(const VideoDecoderConfig&)> NewVideoConfigCB;
-
- EsParserH264(const NewVideoConfigCB& new_video_config_cb,
- const EmitBufferCB& emit_buffer_cb);
- virtual ~EsParserH264();
-
- // EsParser implementation.
- virtual bool Parse(const uint8* buf, int size,
- base::TimeDelta pts,
- base::TimeDelta dts) OVERRIDE;
- virtual void Flush() OVERRIDE;
- virtual void Reset() OVERRIDE;
-
- private:
- struct TimingDesc {
- base::TimeDelta dts;
- base::TimeDelta pts;
- };
-
- // H264 parser.
- // It resumes parsing from byte position |es_pos_|.
- bool ParseInternal();
-
- // Emit a frame if a frame has been started earlier.
- void EmitFrameIfNeeded(int next_aud_pos);
-
- // Start a new frame.
- // Note: if aud_pos < 0, clear the current frame.
- void StartFrame(int aud_pos);
-
- // Discard |nbytes| of ES from the ES byte queue.
- void DiscardEs(int nbytes);
-
- // Parse a NAL / SPS.
- // Returns true if successful (compliant bitstream).
- bool NalParser(const uint8* buf, int size);
- bool ProcessSPS(const uint8* buf, int size);
-
- // Callbacks to pass the stream configuration and the frames.
- NewVideoConfigCB new_video_config_cb_;
- EmitBufferCB emit_buffer_cb_;
-
- // Bytes of the ES stream that have not been emitted yet.
- ByteQueue es_byte_queue_;
- std::list<std::pair<int, TimingDesc> > timing_desc_list_;
-
- // H264 parser state.
- // Note: |current_access_unit_pos_| is pointing to an annexB syncword
- // while |current_nal_pos_| is pointing to the NAL unit
- // (i.e. does not include the annexB syncword).
- int es_pos_;
- int current_nal_pos_;
- int current_access_unit_pos_;
- bool is_key_frame_;
-
- // Last video decoder config.
- VideoDecoderConfig last_video_decoder_config_;
-};
-
-} // namespace mp2t
-} // namespace media
-
-#endif
-
diff --git a/media/mp2t/mp2t_common.h b/media/mp2t/mp2t_common.h
deleted file mode 100644
index 7bc8d7b..0000000
--- a/media/mp2t/mp2t_common.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 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.
-
-#ifndef MEDIA_MP2T_MP2T_COMMON_H_
-#define MEDIA_MP2T_MP2T_COMMON_H_
-
-#define LOG_LEVEL_TS 5
-#define LOG_LEVEL_PES 4
-#define LOG_LEVEL_ES 3
-
-#define RCHECK(x) \
- do { \
- if (!(x)) { \
- DLOG(WARNING) << "Failure while parsing Mpeg2TS: " << #x; \
- return false; \
- } \
- } while (0)
-
-#endif
-
diff --git a/media/mp2t/mp2t_stream_parser.cc b/media/mp2t/mp2t_stream_parser.cc
deleted file mode 100644
index 68fca5c..0000000
--- a/media/mp2t/mp2t_stream_parser.cc
+++ /dev/null
@@ -1,616 +0,0 @@
-// Copyright 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/mp2t_stream_parser.h"
-
-#include "base/bind.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/stl_util.h"
-#include "media/base/audio_decoder_config.h"
-#include "media/base/buffers.h"
-#include "media/base/stream_parser_buffer.h"
-#include "media/base/video_decoder_config.h"
-#include "media/mp2t/es_parser.h"
-#include "media/mp2t/es_parser_adts.h"
-#include "media/mp2t/es_parser_h264.h"
-#include "media/mp2t/mp2t_common.h"
-#include "media/mp2t/ts_packet.h"
-#include "media/mp2t/ts_section.h"
-#include "media/mp2t/ts_section_pat.h"
-#include "media/mp2t/ts_section_pes.h"
-#include "media/mp2t/ts_section_pmt.h"
-
-namespace media {
-namespace mp2t {
-
-enum StreamType {
- // ISO-13818.1 / ITU H.222 Table 2.34 "Stream type assignments"
- kStreamTypeMpeg1Audio = 0x3,
- kStreamTypeAAC = 0xf,
- kStreamTypeAVC = 0x1b,
-};
-
-class PidState {
- public:
- enum PidType {
- kPidPat,
- kPidPmt,
- kPidAudioPes,
- kPidVideoPes,
- };
-
- PidState(int pid, PidType pid_tyoe,
- scoped_ptr<TsSection> section_parser);
-
- // Extract the content of the TS packet and parse it.
- // Return true if successful.
- bool PushTsPacket(const TsPacket& ts_packet);
-
- // Flush the PID state (possibly emitting some pending frames)
- // and reset its state.
- void Flush();
-
- // Enable/disable the PID.
- // Disabling a PID will reset its state and ignore any further incoming TS
- // packets.
- void Enable();
- void Disable();
- bool IsEnabled() const;
-
- PidType pid_type() const { return pid_type_; }
-
- private:
- void ResetState();
-
- int pid_;
- PidType pid_type_;
- scoped_ptr<TsSection> section_parser_;
-
- bool enable_;
-
- int continuity_counter_;
-};
-
-PidState::PidState(int pid, PidType pid_type,
- scoped_ptr<TsSection> section_parser)
- : pid_(pid),
- pid_type_(pid_type),
- section_parser_(section_parser.Pass()),
- enable_(false),
- continuity_counter_(-1) {
- DCHECK(section_parser_);
-}
-
-bool PidState::PushTsPacket(const TsPacket& ts_packet) {
- DCHECK_EQ(ts_packet.pid(), pid_);
-
- // The current PID is not part of the PID filter,
- // just discard the incoming TS packet.
- if (!enable_)
- return true;
-
- int expected_continuity_counter = (continuity_counter_ + 1) % 16;
- if (continuity_counter_ >= 0 &&
- ts_packet.continuity_counter() != expected_continuity_counter) {
- DVLOG(1) << "TS discontinuity detected for pid: " << pid_;
- return false;
- }
-
- bool status = section_parser_->Parse(
- ts_packet.payload_unit_start_indicator(),
- ts_packet.payload(),
- ts_packet.payload_size());
-
- // At the minimum, when parsing failed, auto reset the section parser.
- // Components that use the StreamParser can take further action if needed.
- if (!status) {
- DVLOG(1) << "Parsing failed for pid = " << pid_;
- ResetState();
- }
-
- return status;
-}
-
-void PidState::Flush() {
- section_parser_->Flush();
- ResetState();
-}
-
-void PidState::Enable() {
- enable_ = true;
-}
-
-void PidState::Disable() {
- if (!enable_)
- return;
-
- ResetState();
- enable_ = false;
-}
-
-bool PidState::IsEnabled() const {
- return enable_;
-}
-
-void PidState::ResetState() {
- section_parser_->Reset();
- continuity_counter_ = -1;
-}
-
-Mp2tStreamParser::BufferQueueWithConfig::BufferQueueWithConfig(
- bool is_cfg_sent,
- const AudioDecoderConfig& audio_cfg,
- const VideoDecoderConfig& video_cfg)
- : is_config_sent(is_cfg_sent),
- audio_config(audio_cfg),
- video_config(video_cfg) {
-}
-
-Mp2tStreamParser::BufferQueueWithConfig::~BufferQueueWithConfig() {
-}
-
-Mp2tStreamParser::Mp2tStreamParser()
- : selected_audio_pid_(-1),
- selected_video_pid_(-1),
- is_initialized_(false),
- segment_started_(false),
- first_video_frame_in_segment_(true) {
-}
-
-Mp2tStreamParser::~Mp2tStreamParser() {
- STLDeleteValues(&pids_);
-}
-
-void Mp2tStreamParser::Init(
- const InitCB& init_cb,
- const NewConfigCB& config_cb,
- const NewBuffersCB& new_buffers_cb,
- const NewTextBuffersCB& text_cb,
- const NeedKeyCB& need_key_cb,
- const AddTextTrackCB& add_text_track_cb,
- const NewMediaSegmentCB& new_segment_cb,
- const base::Closure& end_of_segment_cb,
- const LogCB& log_cb) {
- DCHECK(!is_initialized_);
- DCHECK(init_cb_.is_null());
- DCHECK(!init_cb.is_null());
- DCHECK(!config_cb.is_null());
- DCHECK(!new_buffers_cb.is_null());
- DCHECK(!need_key_cb.is_null());
- DCHECK(!end_of_segment_cb.is_null());
-
- init_cb_ = init_cb;
- config_cb_ = config_cb;
- new_buffers_cb_ = new_buffers_cb;
- need_key_cb_ = need_key_cb;
- new_segment_cb_ = new_segment_cb;
- end_of_segment_cb_ = end_of_segment_cb;
- log_cb_ = log_cb;
-}
-
-void Mp2tStreamParser::Flush() {
- DVLOG(1) << "Mp2tStreamParser::Flush";
-
- // Flush the buffers and reset the pids.
- for (std::map<int, PidState*>::iterator it = pids_.begin();
- it != pids_.end(); ++it) {
- DVLOG(1) << "Flushing PID: " << it->first;
- PidState* pid_state = it->second;
- pid_state->Flush();
- delete pid_state;
- }
- pids_.clear();
- EmitRemainingBuffers();
- buffer_queue_chain_.clear();
-
- // End of the segment.
- // Note: does not need to invoke |end_of_segment_cb_| since flushing the
- // stream parser already involves the end of the current segment.
- segment_started_ = false;
- first_video_frame_in_segment_ = true;
-
- // Remove any bytes left in the TS buffer.
- // (i.e. any partial TS packet => less than 188 bytes).
- ts_byte_queue_.Reset();
-
- // Reset the selected PIDs.
- selected_audio_pid_ = -1;
- selected_video_pid_ = -1;
-}
-
-bool Mp2tStreamParser::Parse(const uint8* buf, int size) {
- DVLOG(1) << "Mp2tStreamParser::Parse size=" << size;
-
- // Add the data to the parser state.
- ts_byte_queue_.Push(buf, size);
-
- while (true) {
- const uint8* ts_buffer;
- int ts_buffer_size;
- ts_byte_queue_.Peek(&ts_buffer, &ts_buffer_size);
- if (ts_buffer_size < TsPacket::kPacketSize)
- break;
-
- // Synchronization.
- int skipped_bytes = TsPacket::Sync(ts_buffer, ts_buffer_size);
- if (skipped_bytes > 0) {
- DVLOG(1) << "Packet not aligned on a TS syncword:"
- << " skipped_bytes=" << skipped_bytes;
- ts_byte_queue_.Pop(skipped_bytes);
- continue;
- }
-
- // Parse the TS header, skipping 1 byte if the header is invalid.
- scoped_ptr<TsPacket> ts_packet(TsPacket::Parse(ts_buffer, ts_buffer_size));
- if (!ts_packet) {
- DVLOG(1) << "Error: invalid TS packet";
- ts_byte_queue_.Pop(1);
- continue;
- }
- DVLOG(LOG_LEVEL_TS)
- << "Processing PID=" << ts_packet->pid()
- << " start_unit=" << ts_packet->payload_unit_start_indicator();
-
- // Parse the section.
- std::map<int, PidState*>::iterator it = pids_.find(ts_packet->pid());
- if (it == pids_.end() &&
- ts_packet->pid() == TsSection::kPidPat) {
- // Create the PAT state here if needed.
- scoped_ptr<TsSection> pat_section_parser(
- new TsSectionPat(
- base::Bind(&Mp2tStreamParser::RegisterPmt,
- base::Unretained(this))));
- scoped_ptr<PidState> pat_pid_state(
- new PidState(ts_packet->pid(), PidState::kPidPat,
- pat_section_parser.Pass()));
- pat_pid_state->Enable();
- it = pids_.insert(
- std::pair<int, PidState*>(ts_packet->pid(),
- pat_pid_state.release())).first;
- }
-
- if (it != pids_.end()) {
- if (!it->second->PushTsPacket(*ts_packet))
- return false;
- } else {
- DVLOG(LOG_LEVEL_TS) << "Ignoring TS packet for pid: " << ts_packet->pid();
- }
-
- // Go to the next packet.
- ts_byte_queue_.Pop(TsPacket::kPacketSize);
- }
-
- RCHECK(FinishInitializationIfNeeded());
-
- // Emit the A/V buffers that kept accumulating during TS parsing.
- return EmitRemainingBuffers();
-}
-
-void Mp2tStreamParser::RegisterPmt(int program_number, int pmt_pid) {
- DVLOG(1) << "RegisterPmt:"
- << " program_number=" << program_number
- << " pmt_pid=" << pmt_pid;
-
- // Only one TS program is allowed. Ignore the incoming program map table,
- // if there is already one registered.
- for (std::map<int, PidState*>::iterator it = pids_.begin();
- it != pids_.end(); ++it) {
- PidState* pid_state = it->second;
- if (pid_state->pid_type() == PidState::kPidPmt) {
- DVLOG_IF(1, pmt_pid != it->first) << "More than one program is defined";
- return;
- }
- }
-
- // Create the PMT state here if needed.
- DVLOG(1) << "Create a new PMT parser";
- scoped_ptr<TsSection> pmt_section_parser(
- new TsSectionPmt(
- base::Bind(&Mp2tStreamParser::RegisterPes,
- base::Unretained(this), pmt_pid)));
- scoped_ptr<PidState> pmt_pid_state(
- new PidState(pmt_pid, PidState::kPidPmt, pmt_section_parser.Pass()));
- pmt_pid_state->Enable();
- pids_.insert(std::pair<int, PidState*>(pmt_pid, pmt_pid_state.release()));
-}
-
-void Mp2tStreamParser::RegisterPes(int pmt_pid,
- int pes_pid,
- int stream_type) {
- // TODO(damienv): check there is no mismatch if the entry already exists.
- DVLOG(1) << "RegisterPes:"
- << " pes_pid=" << pes_pid
- << " stream_type=" << std::hex << stream_type << std::dec;
- std::map<int, PidState*>::iterator it = pids_.find(pes_pid);
- if (it != pids_.end())
- return;
-
- // Create a stream parser corresponding to the stream type.
- bool is_audio = false;
- scoped_ptr<EsParser> es_parser;
- if (stream_type == kStreamTypeAVC) {
- es_parser.reset(
- new EsParserH264(
- base::Bind(&Mp2tStreamParser::OnVideoConfigChanged,
- base::Unretained(this),
- pes_pid),
- base::Bind(&Mp2tStreamParser::OnEmitVideoBuffer,
- base::Unretained(this),
- pes_pid)));
- } else if (stream_type == kStreamTypeAAC) {
- es_parser.reset(
- new EsParserAdts(
- base::Bind(&Mp2tStreamParser::OnAudioConfigChanged,
- base::Unretained(this),
- pes_pid),
- base::Bind(&Mp2tStreamParser::OnEmitAudioBuffer,
- base::Unretained(this),
- pes_pid)));
- is_audio = true;
- } else {
- return;
- }
-
- // Create the PES state here.
- DVLOG(1) << "Create a new PES state";
- scoped_ptr<TsSection> pes_section_parser(
- new TsSectionPes(es_parser.Pass()));
- PidState::PidType pid_type =
- is_audio ? PidState::kPidAudioPes : PidState::kPidVideoPes;
- scoped_ptr<PidState> pes_pid_state(
- new PidState(pes_pid, pid_type, pes_section_parser.Pass()));
- pids_.insert(std::pair<int, PidState*>(pes_pid, pes_pid_state.release()));
-
- // A new PES pid has been added, the PID filter might change.
- UpdatePidFilter();
-}
-
-void Mp2tStreamParser::UpdatePidFilter() {
- // Applies the HLS rule to select the default audio/video PIDs:
- // select the audio/video streams with the lowest PID.
- // TODO(damienv): this can be changed when the StreamParser interface
- // supports multiple audio/video streams.
- PidMap::iterator lowest_audio_pid = pids_.end();
- PidMap::iterator lowest_video_pid = pids_.end();
- for (PidMap::iterator it = pids_.begin(); it != pids_.end(); ++it) {
- int pid = it->first;
- PidState* pid_state = it->second;
- if (pid_state->pid_type() == PidState::kPidAudioPes &&
- (lowest_audio_pid == pids_.end() || pid < lowest_audio_pid->first))
- lowest_audio_pid = it;
- if (pid_state->pid_type() == PidState::kPidVideoPes &&
- (lowest_video_pid == pids_.end() || pid < lowest_video_pid->first))
- lowest_video_pid = it;
- }
-
- // Enable both the lowest audio and video PIDs.
- if (lowest_audio_pid != pids_.end()) {
- DVLOG(1) << "Enable audio pid: " << lowest_audio_pid->first;
- lowest_audio_pid->second->Enable();
- selected_audio_pid_ = lowest_audio_pid->first;
- }
- if (lowest_video_pid != pids_.end()) {
- DVLOG(1) << "Enable video pid: " << lowest_audio_pid->first;
- lowest_video_pid->second->Enable();
- selected_video_pid_ = lowest_video_pid->first;
- }
-
- // Disable all the other audio and video PIDs.
- for (PidMap::iterator it = pids_.begin(); it != pids_.end(); ++it) {
- PidState* pid_state = it->second;
- if (it != lowest_audio_pid && it != lowest_video_pid &&
- (pid_state->pid_type() == PidState::kPidAudioPes ||
- pid_state->pid_type() == PidState::kPidVideoPes))
- pid_state->Disable();
- }
-}
-
-void Mp2tStreamParser::OnVideoConfigChanged(
- int pes_pid,
- const VideoDecoderConfig& video_decoder_config) {
- DVLOG(1) << "OnVideoConfigChanged for pid=" << pes_pid;
- DCHECK_EQ(pes_pid, selected_video_pid_);
- DCHECK(video_decoder_config.IsValidConfig());
-
- // Create a new entry in |buffer_queue_chain_| with the updated configs.
- BufferQueueWithConfig buffer_queue_with_config(
- false,
- buffer_queue_chain_.empty()
- ? AudioDecoderConfig() : buffer_queue_chain_.back().audio_config,
- video_decoder_config);
- buffer_queue_chain_.push_back(buffer_queue_with_config);
-
- // Replace any non valid config with the 1st valid entry.
- // This might happen if there was no available config before.
- for (std::list<BufferQueueWithConfig>::iterator it =
- buffer_queue_chain_.begin(); it != buffer_queue_chain_.end(); ++it) {
- if (it->video_config.IsValidConfig())
- break;
- it->video_config = video_decoder_config;
- }
-}
-
-void Mp2tStreamParser::OnAudioConfigChanged(
- int pes_pid,
- const AudioDecoderConfig& audio_decoder_config) {
- DVLOG(1) << "OnAudioConfigChanged for pid=" << pes_pid;
- DCHECK_EQ(pes_pid, selected_audio_pid_);
- DCHECK(audio_decoder_config.IsValidConfig());
-
- // Create a new entry in |buffer_queue_chain_| with the updated configs.
- BufferQueueWithConfig buffer_queue_with_config(
- false,
- audio_decoder_config,
- buffer_queue_chain_.empty()
- ? VideoDecoderConfig() : buffer_queue_chain_.back().video_config);
- buffer_queue_chain_.push_back(buffer_queue_with_config);
-
- // Replace any non valid config with the 1st valid entry.
- // This might happen if there was no available config before.
- for (std::list<BufferQueueWithConfig>::iterator it =
- buffer_queue_chain_.begin(); it != buffer_queue_chain_.end(); ++it) {
- if (it->audio_config.IsValidConfig())
- break;
- it->audio_config = audio_decoder_config;
- }
-}
-
-bool Mp2tStreamParser::FinishInitializationIfNeeded() {
- // Nothing to be done if already initialized.
- if (is_initialized_)
- return true;
-
- // Wait for more data to come to finish initialization.
- if (buffer_queue_chain_.empty())
- return true;
-
- // Wait for more data to come if one of the config is not available.
- BufferQueueWithConfig& queue_with_config = buffer_queue_chain_.front();
- if (selected_audio_pid_ > 0 &&
- !queue_with_config.audio_config.IsValidConfig())
- return true;
- if (selected_video_pid_ > 0 &&
- !queue_with_config.video_config.IsValidConfig())
- return true;
-
- // Pass the config before invoking the initialization callback.
- RCHECK(config_cb_.Run(queue_with_config.audio_config,
- queue_with_config.video_config));
- queue_with_config.is_config_sent = true;
-
- // For Mpeg2 TS, the duration is not known.
- DVLOG(1) << "Mpeg2TS stream parser initialization done";
- init_cb_.Run(true, kInfiniteDuration());
- is_initialized_ = true;
-
- return true;
-}
-
-void Mp2tStreamParser::OnEmitAudioBuffer(
- int pes_pid,
- scoped_refptr<StreamParserBuffer> stream_parser_buffer) {
- DCHECK_EQ(pes_pid, selected_audio_pid_);
-
- DVLOG(LOG_LEVEL_ES)
- << "OnEmitAudioBuffer: "
- << " size="
- << stream_parser_buffer->data_size()
- << " dts="
- << stream_parser_buffer->GetDecodeTimestamp().InMilliseconds()
- << " pts="
- << stream_parser_buffer->timestamp().InMilliseconds();
- stream_parser_buffer->set_timestamp(
- stream_parser_buffer->timestamp() - time_offset_);
- stream_parser_buffer->SetDecodeTimestamp(
- stream_parser_buffer->GetDecodeTimestamp() - time_offset_);
-
- // Ignore the incoming buffer if it is not associated with any config.
- if (buffer_queue_chain_.empty()) {
- DVLOG(1) << "Ignoring audio buffer with no corresponding audio config";
- return;
- }
-
- buffer_queue_chain_.back().audio_queue.push_back(stream_parser_buffer);
-}
-
-void Mp2tStreamParser::OnEmitVideoBuffer(
- int pes_pid,
- scoped_refptr<StreamParserBuffer> stream_parser_buffer) {
- DCHECK_EQ(pes_pid, selected_video_pid_);
-
- DVLOG(LOG_LEVEL_ES)
- << "OnEmitVideoBuffer"
- << " size="
- << stream_parser_buffer->data_size()
- << " dts="
- << stream_parser_buffer->GetDecodeTimestamp().InMilliseconds()
- << " pts="
- << stream_parser_buffer->timestamp().InMilliseconds()
- << " IsKeyframe="
- << stream_parser_buffer->IsKeyframe();
- stream_parser_buffer->set_timestamp(
- stream_parser_buffer->timestamp() - time_offset_);
- stream_parser_buffer->SetDecodeTimestamp(
- stream_parser_buffer->GetDecodeTimestamp() - time_offset_);
-
- // Ignore the incoming buffer if it is not associated with any config.
- if (buffer_queue_chain_.empty()) {
- DVLOG(1) << "Ignoring video buffer with no corresponding video config:"
- << " keyframe=" << stream_parser_buffer->IsKeyframe()
- << " dts="
- << stream_parser_buffer->GetDecodeTimestamp().InMilliseconds();
- return;
- }
-
- // A segment cannot start with a non key frame.
- // Ignore the frame if that's the case.
- if (first_video_frame_in_segment_ && !stream_parser_buffer->IsKeyframe()) {
- DVLOG(1) << "Ignoring non-key frame:"
- << " dts="
- << stream_parser_buffer->GetDecodeTimestamp().InMilliseconds();
- return;
- }
-
- first_video_frame_in_segment_ = false;
- buffer_queue_chain_.back().video_queue.push_back(stream_parser_buffer);
-}
-
-bool Mp2tStreamParser::EmitRemainingBuffers() {
- DVLOG(LOG_LEVEL_ES) << "Mp2tStreamParser::EmitRemainingBuffers";
-
- // No buffer should be sent until fully initialized.
- if (!is_initialized_)
- return true;
-
- if (buffer_queue_chain_.empty())
- return true;
-
- // Keep track of the last audio and video config sent.
- AudioDecoderConfig last_audio_config =
- buffer_queue_chain_.back().audio_config;
- VideoDecoderConfig last_video_config =
- buffer_queue_chain_.back().video_config;
-
- // Buffer emission.
- while (!buffer_queue_chain_.empty()) {
- // Start a segment if needed.
- if (!segment_started_) {
- DVLOG(1) << "Starting a new segment";
- segment_started_ = true;
- new_segment_cb_.Run();
- }
-
- // Update the audio and video config if needed.
- BufferQueueWithConfig& queue_with_config = buffer_queue_chain_.front();
- if (!queue_with_config.is_config_sent) {
- if (!config_cb_.Run(queue_with_config.audio_config,
- queue_with_config.video_config))
- return false;
- queue_with_config.is_config_sent = true;
- }
-
- // Add buffers.
- if (!queue_with_config.audio_queue.empty() ||
- !queue_with_config.video_queue.empty()) {
- if (!new_buffers_cb_.Run(queue_with_config.audio_queue,
- queue_with_config.video_queue)) {
- return false;
- }
- }
-
- buffer_queue_chain_.pop_front();
- }
-
- // Push an empty queue with the last audio/video config
- // so that buffers with the same config can be added later on.
- BufferQueueWithConfig queue_with_config(
- true, last_audio_config, last_video_config);
- buffer_queue_chain_.push_back(queue_with_config);
-
- return true;
-}
-
-} // namespace mp2t
-} // namespace media
-
diff --git a/media/mp2t/mp2t_stream_parser.h b/media/mp2t/mp2t_stream_parser.h
deleted file mode 100644
index dcab559..0000000
--- a/media/mp2t/mp2t_stream_parser.h
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright 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.
-
-#ifndef MEDIA_MP2T_MP2T_STREAM_PARSER_H_
-#define MEDIA_MP2T_MP2T_STREAM_PARSER_H_
-
-#include <list>
-#include <map>
-
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "media/base/audio_decoder_config.h"
-#include "media/base/byte_queue.h"
-#include "media/base/media_export.h"
-#include "media/base/stream_parser.h"
-#include "media/base/video_decoder_config.h"
-
-namespace media {
-
-class StreamParserBuffer;
-
-namespace mp2t {
-
-class PidState;
-
-class MEDIA_EXPORT Mp2tStreamParser : public StreamParser {
- public:
- Mp2tStreamParser();
- virtual ~Mp2tStreamParser();
-
- // StreamParser implementation.
- virtual void Init(const InitCB& init_cb,
- const NewConfigCB& config_cb,
- const NewBuffersCB& new_buffers_cb,
- const NewTextBuffersCB& text_cb,
- const NeedKeyCB& need_key_cb,
- const AddTextTrackCB& add_text_track_cb,
- const NewMediaSegmentCB& new_segment_cb,
- const base::Closure& end_of_segment_cb,
- const LogCB& log_cb) OVERRIDE;
- virtual void Flush() OVERRIDE;
- virtual bool Parse(const uint8* buf, int size) OVERRIDE;
-
- private:
- typedef std::map<int, PidState*> PidMap;
-
- struct BufferQueueWithConfig {
- BufferQueueWithConfig(bool is_cfg_sent,
- const AudioDecoderConfig& audio_cfg,
- const VideoDecoderConfig& video_cfg);
- ~BufferQueueWithConfig();
-
- bool is_config_sent;
- AudioDecoderConfig audio_config;
- StreamParser::BufferQueue audio_queue;
- VideoDecoderConfig video_config;
- StreamParser::BufferQueue video_queue;
- };
-
- // Callback invoked to register a Program Map Table.
- // Note: Does nothing if the PID is already registered.
- void RegisterPmt(int program_number, int pmt_pid);
-
- // Callback invoked to register a PES pid.
- // Possible values for |stream_type| are defined in:
- // ISO-13818.1 / ITU H.222 Table 2.34 "Stream type assignments".
- // |pes_pid| is part of the Program Map Table refered by |pmt_pid|.
- void RegisterPes(int pmt_pid, int pes_pid, int stream_type);
-
- // Since the StreamParser interface allows only one audio & video streams,
- // an automatic PID filtering should be applied to select the audio & video
- // streams.
- void UpdatePidFilter();
-
- // Callback invoked each time the audio/video decoder configuration is
- // changed.
- void OnVideoConfigChanged(int pes_pid,
- const VideoDecoderConfig& video_decoder_config);
- void OnAudioConfigChanged(int pes_pid,
- const AudioDecoderConfig& audio_decoder_config);
-
- // Invoke the initialization callback if needed.
- bool FinishInitializationIfNeeded();
-
- // Callback invoked by the ES stream parser
- // to emit a new audio/video access unit.
- void OnEmitAudioBuffer(
- int pes_pid,
- scoped_refptr<StreamParserBuffer> stream_parser_buffer);
- void OnEmitVideoBuffer(
- int pes_pid,
- scoped_refptr<StreamParserBuffer> stream_parser_buffer);
- bool EmitRemainingBuffers();
-
- // List of callbacks.
- InitCB init_cb_;
- NewConfigCB config_cb_;
- NewBuffersCB new_buffers_cb_;
- NeedKeyCB need_key_cb_;
- NewMediaSegmentCB new_segment_cb_;
- base::Closure end_of_segment_cb_;
- LogCB log_cb_;
-
- // Bytes of the TS stream.
- ByteQueue ts_byte_queue_;
-
- // List of PIDs and their state.
- PidMap pids_;
-
- // Selected audio and video PIDs.
- int selected_audio_pid_;
- int selected_video_pid_;
-
- // Pending audio & video buffers.
- std::list<BufferQueueWithConfig> buffer_queue_chain_;
-
- // Whether |init_cb_| has been invoked.
- bool is_initialized_;
-
- // Indicate whether a segment was started.
- bool segment_started_;
- bool first_video_frame_in_segment_;
- base::TimeDelta time_offset_;
-
- DISALLOW_COPY_AND_ASSIGN(Mp2tStreamParser);
-};
-
-} // namespace mp2t
-} // namespace media
-
-#endif
-
diff --git a/media/mp2t/mp2t_stream_parser_unittest.cc b/media/mp2t/mp2t_stream_parser_unittest.cc
deleted file mode 100644
index 12a3b95..0000000
--- a/media/mp2t/mp2t_stream_parser_unittest.cc
+++ /dev/null
@@ -1,189 +0,0 @@
-// Copyright 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 <algorithm>
-#include <string>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/logging.h"
-#include "base/memory/ref_counted.h"
-#include "base/time/time.h"
-#include "media/base/audio_decoder_config.h"
-#include "media/base/decoder_buffer.h"
-#include "media/base/stream_parser_buffer.h"
-#include "media/base/test_data_util.h"
-#include "media/base/video_decoder_config.h"
-#include "media/mp2t/mp2t_stream_parser.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace media {
-namespace mp2t {
-
-class Mp2tStreamParserTest : public testing::Test {
- public:
- Mp2tStreamParserTest()
- : audio_frame_count_(0),
- video_frame_count_(0),
- video_min_dts_(kNoTimestamp()),
- video_max_dts_(kNoTimestamp()) {
- parser_.reset(new Mp2tStreamParser());
- }
-
- protected:
- scoped_ptr<Mp2tStreamParser> parser_;
- int audio_frame_count_;
- int video_frame_count_;
- base::TimeDelta video_min_dts_;
- base::TimeDelta video_max_dts_;
-
- bool AppendData(const uint8* data, size_t length) {
- return parser_->Parse(data, length);
- }
-
- bool AppendDataInPieces(const uint8* data, size_t length, size_t piece_size) {
- const uint8* start = data;
- const uint8* end = data + length;
- while (start < end) {
- size_t append_size = std::min(piece_size,
- static_cast<size_t>(end - start));
- if (!AppendData(start, append_size))
- return false;
- start += append_size;
- }
- return true;
- }
-
- void OnInit(bool init_ok, base::TimeDelta duration) {
- DVLOG(1) << "OnInit: ok=" << init_ok
- << ", dur=" << duration.InMilliseconds();
- }
-
- bool OnNewConfig(const AudioDecoderConfig& ac, const VideoDecoderConfig& vc) {
- DVLOG(1) << "OnNewConfig: audio=" << ac.IsValidConfig()
- << ", video=" << vc.IsValidConfig();
- return true;
- }
-
-
- void DumpBuffers(const std::string& label,
- const StreamParser::BufferQueue& buffers) {
- DVLOG(2) << "DumpBuffers: " << label << " size " << buffers.size();
- for (StreamParser::BufferQueue::const_iterator buf = buffers.begin();
- buf != buffers.end(); buf++) {
- DVLOG(3) << " n=" << buf - buffers.begin()
- << ", size=" << (*buf)->data_size()
- << ", dur=" << (*buf)->duration().InMilliseconds();
- }
- }
-
- bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers,
- const StreamParser::BufferQueue& video_buffers) {
- DumpBuffers("audio_buffers", audio_buffers);
- DumpBuffers("video_buffers", video_buffers);
- audio_frame_count_ += audio_buffers.size();
- video_frame_count_ += video_buffers.size();
-
- if (video_min_dts_ == kNoTimestamp() && !video_buffers.empty())
- video_min_dts_ = video_buffers.front()->GetDecodeTimestamp();
- if (!video_buffers.empty()) {
- video_max_dts_ = video_buffers.back()->GetDecodeTimestamp();
- // Verify monotonicity.
- StreamParser::BufferQueue::const_iterator it1 = video_buffers.begin();
- StreamParser::BufferQueue::const_iterator it2 = ++it1;
- for ( ; it2 != video_buffers.end(); ++it1, ++it2) {
- if ((*it2)->GetDecodeTimestamp() < (*it1)->GetDecodeTimestamp())
- return false;
- }
- }
-
- return true;
- }
-
- bool OnNewTextBuffers(TextTrack* text_track,
- const StreamParser::BufferQueue& buffers) {
- return true;
- }
-
- void OnKeyNeeded(const std::string& type,
- const std::vector<uint8>& init_data) {
- DVLOG(1) << "OnKeyNeeded: " << init_data.size();
- }
-
- scoped_ptr<TextTrack> OnAddTextTrack(
- TextKind kind,
- const std::string& label,
- const std::string& language) {
- return scoped_ptr<TextTrack>();
- }
-
- void OnNewSegment() {
- DVLOG(1) << "OnNewSegment";
- }
-
- void OnEndOfSegment() {
- DVLOG(1) << "OnEndOfSegment()";
- }
-
- void InitializeParser() {
- parser_->Init(
- base::Bind(&Mp2tStreamParserTest::OnInit,
- base::Unretained(this)),
- base::Bind(&Mp2tStreamParserTest::OnNewConfig,
- base::Unretained(this)),
- base::Bind(&Mp2tStreamParserTest::OnNewBuffers,
- base::Unretained(this)),
- base::Bind(&Mp2tStreamParserTest::OnNewTextBuffers,
- base::Unretained(this)),
- base::Bind(&Mp2tStreamParserTest::OnKeyNeeded,
- base::Unretained(this)),
- base::Bind(&Mp2tStreamParserTest::OnAddTextTrack,
- base::Unretained(this)),
- base::Bind(&Mp2tStreamParserTest::OnNewSegment,
- base::Unretained(this)),
- base::Bind(&Mp2tStreamParserTest::OnEndOfSegment,
- base::Unretained(this)),
- LogCB());
- }
-
- bool ParseMpeg2TsFile(const std::string& filename, int append_bytes) {
- InitializeParser();
-
- scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(filename);
- EXPECT_TRUE(AppendDataInPieces(buffer->data(),
- buffer->data_size(),
- append_bytes));
- return true;
- }
-};
-
-TEST_F(Mp2tStreamParserTest, UnalignedAppend17) {
- // Test small, non-segment-aligned appends.
- ParseMpeg2TsFile("bear-1280x720.ts", 17);
- EXPECT_EQ(video_frame_count_, 81);
- parser_->Flush();
- EXPECT_EQ(video_frame_count_, 82);
-}
-
-TEST_F(Mp2tStreamParserTest, UnalignedAppend512) {
- // Test small, non-segment-aligned appends.
- ParseMpeg2TsFile("bear-1280x720.ts", 512);
- EXPECT_EQ(video_frame_count_, 81);
- parser_->Flush();
- EXPECT_EQ(video_frame_count_, 82);
-}
-
-TEST_F(Mp2tStreamParserTest, TimestampWrapAround) {
- // "bear-1280x720_ptswraparound.ts" has been transcoded
- // from bear-1280x720.mp4 by applying a time offset of 95442s
- // (close to 2^33 / 90000) which results in timestamps wrap around
- // in the Mpeg2 TS stream.
- ParseMpeg2TsFile("bear-1280x720_ptswraparound.ts", 512);
- EXPECT_EQ(video_frame_count_, 81);
- EXPECT_GE(video_min_dts_, base::TimeDelta::FromSeconds(95443 - 10));
- EXPECT_LE(video_max_dts_, base::TimeDelta::FromSeconds(95443 + 10));
-}
-
-} // namespace mp2t
-} // namespace media
diff --git a/media/mp2t/ts_packet.cc b/media/mp2t/ts_packet.cc
deleted file mode 100644
index 4162690..0000000
--- a/media/mp2t/ts_packet.cc
+++ /dev/null
@@ -1,209 +0,0 @@
-// Copyright 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
-
diff --git a/media/mp2t/ts_packet.h b/media/mp2t/ts_packet.h
deleted file mode 100644
index f3537bc..0000000
--- a/media/mp2t/ts_packet.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 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.
-
-#ifndef MEDIA_MP2T_TS_PACKET_H_
-#define MEDIA_MP2T_TS_PACKET_H_
-
-#include "base/basictypes.h"
-
-namespace media {
-
-class BitReader;
-
-namespace mp2t {
-
-class TsPacket {
- public:
- static const int kPacketSize = 188;
-
- // Return the number of bytes to discard
- // to be synchronized on a TS syncword.
- static int Sync(const uint8* buf, int size);
-
- // Parse a TS packet.
- // Return a TsPacket only when parsing was successful.
- // Return NULL otherwise.
- static TsPacket* Parse(const uint8* buf, int size);
-
- ~TsPacket();
-
- // TS header accessors.
- bool payload_unit_start_indicator() const {
- return payload_unit_start_indicator_;
- }
- int pid() const { return pid_; }
- int continuity_counter() const { return continuity_counter_; }
- bool discontinuity_indicator() const { return discontinuity_indicator_; }
- bool random_access_indicator() const { return random_access_indicator_; }
-
- // Return the offset and the size of the payload.
- const uint8* payload() const { return payload_; }
- int payload_size() const { return payload_size_; }
-
- private:
- TsPacket();
-
- // Parse an Mpeg2 TS header.
- // The buffer size should be at least |kPacketSize|
- bool ParseHeader(const uint8* buf);
- bool ParseAdaptationField(BitReader* bit_reader,
- int adaptation_field_length);
-
- // Size of the payload.
- const uint8* payload_;
- int payload_size_;
-
- // TS header.
- bool payload_unit_start_indicator_;
- int pid_;
- int continuity_counter_;
-
- // Params from the adaptation field.
- bool discontinuity_indicator_;
- bool random_access_indicator_;
-
- DISALLOW_COPY_AND_ASSIGN(TsPacket);
-};
-
-} // namespace mp2t
-} // namespace media
-
-#endif
-
diff --git a/media/mp2t/ts_section.h b/media/mp2t/ts_section.h
deleted file mode 100644
index 1b7453f..0000000
--- a/media/mp2t/ts_section.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 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.
-
-#ifndef MEDIA_MP2T_TS_SECTION_H_
-#define MEDIA_MP2T_TS_SECTION_H_
-
-namespace media {
-namespace mp2t {
-
-class TsSection {
- public:
- // From ISO/IEC 13818-1 or ITU H.222 spec: Table 2-3 - PID table.
- enum SpecialPid {
- kPidPat = 0x0,
- kPidCat = 0x1,
- kPidTsdt = 0x2,
- kPidNullPacket = 0x1fff,
- kPidMax = 0x1fff,
- };
-
- virtual ~TsSection() {}
-
- // Parse the data bytes of the TS packet.
- // Return true if parsing is successful.
- virtual bool Parse(bool payload_unit_start_indicator,
- const uint8* buf, int size) = 0;
-
- // Process bytes that have not been processed yet (pending buffers in the
- // pipe). Flush might thus results in frame emission, as an example.
- virtual void Flush() = 0;
-
- // Reset the state of the parser to its initial state.
- virtual void Reset() = 0;
-};
-
-} // namespace mp2t
-} // namespace media
-
-#endif
diff --git a/media/mp2t/ts_section_pat.cc b/media/mp2t/ts_section_pat.cc
deleted file mode 100644
index 7ba6f7b..0000000
--- a/media/mp2t/ts_section_pat.cc
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright 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_section_pat.h"
-
-#include <vector>
-
-#include "base/logging.h"
-#include "media/base/bit_reader.h"
-#include "media/mp2t/mp2t_common.h"
-
-namespace media {
-namespace mp2t {
-
-TsSectionPat::TsSectionPat(const RegisterPmtCb& register_pmt_cb)
- : register_pmt_cb_(register_pmt_cb),
- version_number_(-1) {
-}
-
-TsSectionPat::~TsSectionPat() {
-}
-
-bool TsSectionPat::ParsePsiSection(BitReader* bit_reader) {
- // Read the fixed section length.
- int table_id;
- bool section_syntax_indicator;
- bool dummy_zero;
- int reserved;
- int section_length;
- int transport_stream_id;
- int version_number;
- bool current_next_indicator;
- int section_number;
- int last_section_number;
- RCHECK(bit_reader->ReadBits(8, &table_id));
- RCHECK(bit_reader->ReadBits(1, &section_syntax_indicator));
- RCHECK(bit_reader->ReadBits(1, &dummy_zero));
- RCHECK(bit_reader->ReadBits(2, &reserved));
- RCHECK(bit_reader->ReadBits(12, &section_length));
- RCHECK(section_length >= 5);
- RCHECK(section_length <= 1021);
- RCHECK(bit_reader->ReadBits(16, &transport_stream_id));
- RCHECK(bit_reader->ReadBits(2, &reserved));
- RCHECK(bit_reader->ReadBits(5, &version_number));
- RCHECK(bit_reader->ReadBits(1, &current_next_indicator));
- RCHECK(bit_reader->ReadBits(8, &section_number));
- RCHECK(bit_reader->ReadBits(8, &last_section_number));
- section_length -= 5;
-
- // Perform a few verifications:
- // - Table ID should be 0 for a PAT.
- // - section_syntax_indicator should be one.
- // - section length should not exceed 1021
- RCHECK(table_id == 0x0);
- RCHECK(section_syntax_indicator);
- RCHECK(!dummy_zero);
-
- // Both the program table and the CRC have a size multiple of 4.
- // Note for pmt_pid_count: minus 4 to account for the CRC.
- RCHECK((section_length % 4) == 0);
- int pmt_pid_count = (section_length - 4) / 4;
-
- // Read the variable length section: program table & crc.
- std::vector<int> program_number_array(pmt_pid_count);
- std::vector<int> pmt_pid_array(pmt_pid_count);
- for (int k = 0; k < pmt_pid_count; k++) {
- int reserved;
- RCHECK(bit_reader->ReadBits(16, &program_number_array[k]));
- RCHECK(bit_reader->ReadBits(3, &reserved));
- RCHECK(bit_reader->ReadBits(13, &pmt_pid_array[k]));
- }
- int crc32;
- RCHECK(bit_reader->ReadBits(32, &crc32));
-
- // Just ignore the PAT if not applicable yet.
- if (!current_next_indicator) {
- DVLOG(1) << "Not supported: received a PAT not applicable yet";
- return true;
- }
-
- // Ignore the program table if it hasn't changed.
- if (version_number == version_number_)
- return true;
-
- // Both the MSE and the HLS spec specifies that TS streams should convey
- // exactly one program.
- if (pmt_pid_count > 1) {
- DVLOG(1) << "Multiple programs detected in the Mpeg2 TS stream";
- return false;
- }
-
- // Can now register the PMT.
-#if !defined(NDEBUG)
- int expected_version_number = version_number;
- if (version_number_ >= 0)
- expected_version_number = (version_number_ + 1) % 32;
- DVLOG_IF(1, version_number != expected_version_number)
- << "Unexpected version number: "
- << version_number << " vs " << version_number_;
-#endif
- for (int k = 0; k < pmt_pid_count; k++) {
- if (program_number_array[k] != 0) {
- // Program numbers different from 0 correspond to PMT.
- register_pmt_cb_.Run(program_number_array[k], pmt_pid_array[k]);
- // Even if there are multiple programs, only one can be supported now.
- // HLS: "Transport Stream segments MUST contain a single MPEG-2 Program."
- break;
- }
- }
- version_number_ = version_number;
-
- return true;
-}
-
-void TsSectionPat::ResetPsiSection() {
- version_number_ = -1;
-}
-
-} // namespace mp2t
-} // namespace media
-
diff --git a/media/mp2t/ts_section_pat.h b/media/mp2t/ts_section_pat.h
deleted file mode 100644
index 84f33de..0000000
--- a/media/mp2t/ts_section_pat.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 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.
-
-#ifndef MEDIA_MP2T_TS_SECTION_PAT_H_
-#define MEDIA_MP2T_TS_SECTION_PAT_H_
-
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "media/mp2t/ts_section_psi.h"
-
-namespace media {
-namespace mp2t {
-
-class TsSectionPat : public TsSectionPsi {
- public:
- // RegisterPmtCb::Run(int program_number, int pmt_pid);
- typedef base::Callback<void(int, int)> RegisterPmtCb;
-
- explicit TsSectionPat(const RegisterPmtCb& register_pmt_cb);
- virtual ~TsSectionPat();
-
- // TsSectionPsi implementation.
- virtual bool ParsePsiSection(BitReader* bit_reader) OVERRIDE;
- virtual void ResetPsiSection() OVERRIDE;
-
- private:
- RegisterPmtCb register_pmt_cb_;
-
- // Parameters from the PAT.
- int version_number_;
-
- DISALLOW_COPY_AND_ASSIGN(TsSectionPat);
-};
-
-} // namespace mp2t
-} // namespace media
-
-#endif
-
diff --git a/media/mp2t/ts_section_pes.cc b/media/mp2t/ts_section_pes.cc
deleted file mode 100644
index 6ff0bf1..0000000
--- a/media/mp2t/ts_section_pes.cc
+++ /dev/null
@@ -1,312 +0,0 @@
-// Copyright 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_section_pes.h"
-
-#include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
-#include "media/base/bit_reader.h"
-#include "media/base/buffers.h"
-#include "media/mp2t/es_parser.h"
-#include "media/mp2t/mp2t_common.h"
-
-static const int kPesStartCode = 0x000001;
-
-// Given that |time| is coded using 33 bits,
-// UnrollTimestamp returns the corresponding unrolled timestamp.
-// The unrolled timestamp is defined by:
-// |time| + k * (2 ^ 33)
-// where k is estimated so that the unrolled timestamp
-// is as close as possible to |previous_unrolled_time|.
-static int64 UnrollTimestamp(int64 previous_unrolled_time, int64 time) {
- // Mpeg2 TS timestamps have an accuracy of 33 bits.
- const int nbits = 33;
-
- // |timestamp| has a precision of |nbits|
- // so make sure the highest bits are set to 0.
- DCHECK_EQ((time >> nbits), 0);
-
- // Consider 3 possibilities to estimate the missing high bits of |time|.
- int64 previous_unrolled_time_high =
- (previous_unrolled_time >> nbits);
- int64 time0 = ((previous_unrolled_time_high - 1) << nbits) | time;
- int64 time1 = ((previous_unrolled_time_high + 0) << nbits) | time;
- int64 time2 = ((previous_unrolled_time_high + 1) << nbits) | time;
-
- // Select the min absolute difference with the current time
- // so as to ensure time continuity.
- int64 diff0 = time0 - previous_unrolled_time;
- int64 diff1 = time1 - previous_unrolled_time;
- int64 diff2 = time2 - previous_unrolled_time;
- if (diff0 < 0)
- diff0 = -diff0;
- if (diff1 < 0)
- diff1 = -diff1;
- if (diff2 < 0)
- diff2 = -diff2;
-
- int64 unrolled_time;
- int64 min_diff;
- if (diff1 < diff0) {
- unrolled_time = time1;
- min_diff = diff1;
- } else {
- unrolled_time = time0;
- min_diff = diff0;
- }
- if (diff2 < min_diff)
- unrolled_time = time2;
-
- return unrolled_time;
-}
-
-static bool IsTimestampSectionValid(int64 timestamp_section) {
- // |pts_section| has 40 bits:
- // - starting with either '0010' or '0011' or '0001'
- // - and ending with a marker bit.
- // See ITU H.222 standard - PES section.
-
- // Verify that all the marker bits are set to one.
- return ((timestamp_section & 0x1) != 0) &&
- ((timestamp_section & 0x10000) != 0) &&
- ((timestamp_section & 0x100000000) != 0);
-}
-
-static int64 ConvertTimestampSectionToTimestamp(int64 timestamp_section) {
- return (((timestamp_section >> 33) & 0x7) << 30) |
- (((timestamp_section >> 17) & 0x7fff) << 15) |
- (((timestamp_section >> 1) & 0x7fff) << 0);
-}
-
-namespace media {
-namespace mp2t {
-
-TsSectionPes::TsSectionPes(scoped_ptr<EsParser> es_parser)
- : es_parser_(es_parser.release()),
- wait_for_pusi_(true),
- previous_pts_valid_(false),
- previous_pts_(0),
- previous_dts_valid_(false),
- previous_dts_(0) {
- DCHECK(es_parser_);
-}
-
-TsSectionPes::~TsSectionPes() {
-}
-
-bool TsSectionPes::Parse(bool payload_unit_start_indicator,
- const uint8* buf, int size) {
- // Ignore partial PES.
- if (wait_for_pusi_ && !payload_unit_start_indicator)
- return true;
-
- bool parse_result = true;
- if (payload_unit_start_indicator) {
- // Try emitting a packet since we might have a pending PES packet
- // with an undefined size.
- // In this case, a unit is emitted when the next unit is coming.
- int raw_pes_size;
- const uint8* raw_pes;
- pes_byte_queue_.Peek(&raw_pes, &raw_pes_size);
- if (raw_pes_size > 0)
- parse_result = Emit(true);
-
- // Reset the state.
- ResetPesState();
-
- // Update the state.
- wait_for_pusi_ = false;
- }
-
- // Add the data to the parser state.
- if (size > 0)
- pes_byte_queue_.Push(buf, size);
-
- // Try emitting the current PES packet.
- return (parse_result && Emit(false));
-}
-
-void TsSectionPes::Flush() {
- // Try emitting a packet since we might have a pending PES packet
- // with an undefined size.
- Emit(true);
-
- // Flush the underlying ES parser.
- es_parser_->Flush();
-}
-
-void TsSectionPes::Reset() {
- ResetPesState();
-
- previous_pts_valid_ = false;
- previous_pts_ = 0;
- previous_dts_valid_ = false;
- previous_dts_ = 0;
-
- es_parser_->Reset();
-}
-
-bool TsSectionPes::Emit(bool emit_for_unknown_size) {
- int raw_pes_size;
- const uint8* raw_pes;
- pes_byte_queue_.Peek(&raw_pes, &raw_pes_size);
-
- // A PES should be at least 6 bytes.
- // Wait for more data to come if not enough bytes.
- if (raw_pes_size < 6)
- return true;
-
- // Check whether we have enough data to start parsing.
- int pes_packet_length =
- (static_cast<int>(raw_pes[4]) << 8) |
- (static_cast<int>(raw_pes[5]));
- if ((pes_packet_length == 0 && !emit_for_unknown_size) ||
- (pes_packet_length != 0 && raw_pes_size < pes_packet_length + 6)) {
- // Wait for more data to come either because:
- // - there are not enough bytes,
- // - or the PES size is unknown and the "force emit" flag is not set.
- // (PES size might be unknown for video PES packet).
- return true;
- }
- DVLOG(LOG_LEVEL_PES) << "pes_packet_length=" << pes_packet_length;
-
- // Parse the packet.
- bool parse_result = ParseInternal(raw_pes, raw_pes_size);
-
- // Reset the state.
- ResetPesState();
-
- return parse_result;
-}
-
-bool TsSectionPes::ParseInternal(const uint8* raw_pes, int raw_pes_size) {
- BitReader bit_reader(raw_pes, raw_pes_size);
-
- // Read up to the pes_packet_length (6 bytes).
- int packet_start_code_prefix;
- int stream_id;
- int pes_packet_length;
- RCHECK(bit_reader.ReadBits(24, &packet_start_code_prefix));
- RCHECK(bit_reader.ReadBits(8, &stream_id));
- RCHECK(bit_reader.ReadBits(16, &pes_packet_length));
-
- RCHECK(packet_start_code_prefix == kPesStartCode);
- DVLOG(LOG_LEVEL_PES) << "stream_id=" << std::hex << stream_id << std::dec;
- if (pes_packet_length == 0)
- pes_packet_length = bit_reader.bits_available() / 8;
-
- // Ignore the PES for unknown stream IDs.
- // See ITU H.222 Table 2-22 "Stream_id assignments"
- bool is_audio_stream_id = ((stream_id & 0xe0) == 0xc0);
- bool is_video_stream_id = ((stream_id & 0xf0) == 0xe0);
- if (!is_audio_stream_id && !is_video_stream_id)
- return true;
-
- // Read up to "pes_header_data_length".
- int dummy_2;
- int PES_scrambling_control;
- bool PES_priority;
- bool data_alignment_indicator;
- bool copyright;
- bool original_or_copy;
- int pts_dts_flags;
- bool escr_flag;
- bool es_rate_flag;
- bool dsm_trick_mode_flag;
- bool additional_copy_info_flag;
- bool pes_crc_flag;
- bool pes_extension_flag;
- int pes_header_data_length;
- RCHECK(bit_reader.ReadBits(2, &dummy_2));
- RCHECK(dummy_2 == 0x2);
- RCHECK(bit_reader.ReadBits(2, &PES_scrambling_control));
- RCHECK(bit_reader.ReadBits(1, &PES_priority));
- RCHECK(bit_reader.ReadBits(1, &data_alignment_indicator));
- RCHECK(bit_reader.ReadBits(1, &copyright));
- RCHECK(bit_reader.ReadBits(1, &original_or_copy));
- RCHECK(bit_reader.ReadBits(2, &pts_dts_flags));
- RCHECK(bit_reader.ReadBits(1, &escr_flag));
- RCHECK(bit_reader.ReadBits(1, &es_rate_flag));
- RCHECK(bit_reader.ReadBits(1, &dsm_trick_mode_flag));
- RCHECK(bit_reader.ReadBits(1, &additional_copy_info_flag));
- RCHECK(bit_reader.ReadBits(1, &pes_crc_flag));
- RCHECK(bit_reader.ReadBits(1, &pes_extension_flag));
- RCHECK(bit_reader.ReadBits(8, &pes_header_data_length));
- int pes_header_start_size = bit_reader.bits_available() / 8;
-
- // Compute the size and the offset of the ES payload.
- // "6" for the 6 bytes read before and including |pes_packet_length|.
- // "3" for the 3 bytes read before and including |pes_header_data_length|.
- int es_size = pes_packet_length - 3 - pes_header_data_length;
- int es_offset = 6 + 3 + pes_header_data_length;
- RCHECK(es_size >= 0);
- RCHECK(es_offset + es_size <= raw_pes_size);
-
- // Read the timing information section.
- bool is_pts_valid = false;
- bool is_dts_valid = false;
- int64 pts_section = 0;
- int64 dts_section = 0;
- if (pts_dts_flags == 0x2) {
- RCHECK(bit_reader.ReadBits(40, &pts_section));
- RCHECK((((pts_section >> 36) & 0xf) == 0x2) &&
- IsTimestampSectionValid(pts_section));
- is_pts_valid = true;
- }
- if (pts_dts_flags == 0x3) {
- RCHECK(bit_reader.ReadBits(40, &pts_section));
- RCHECK(bit_reader.ReadBits(40, &dts_section));
- RCHECK((((pts_section >> 36) & 0xf) == 0x3) &&
- IsTimestampSectionValid(pts_section));
- RCHECK((((dts_section >> 36) & 0xf) == 0x1) &&
- IsTimestampSectionValid(dts_section));
- is_pts_valid = true;
- is_dts_valid = true;
- }
-
- // Convert and unroll the timestamps.
- base::TimeDelta media_pts(kNoTimestamp());
- base::TimeDelta media_dts(kNoTimestamp());
- if (is_pts_valid) {
- int64 pts = ConvertTimestampSectionToTimestamp(pts_section);
- if (previous_pts_valid_)
- pts = UnrollTimestamp(previous_pts_, pts);
- previous_pts_ = pts;
- previous_pts_valid_ = true;
- media_pts = base::TimeDelta::FromMicroseconds((1000 * pts) / 90);
- }
- if (is_dts_valid) {
- int64 dts = ConvertTimestampSectionToTimestamp(dts_section);
- if (previous_dts_valid_)
- dts = UnrollTimestamp(previous_dts_, dts);
- previous_dts_ = dts;
- previous_dts_valid_ = true;
- media_dts = base::TimeDelta::FromMicroseconds((1000 * dts) / 90);
- }
-
- // Discard the rest of the PES packet header.
- // TODO(damienv): check if some info of the PES packet header are useful.
- DCHECK_EQ(bit_reader.bits_available() % 8, 0);
- int pes_header_remaining_size = pes_header_data_length -
- (pes_header_start_size - bit_reader.bits_available() / 8);
- RCHECK(pes_header_remaining_size >= 0);
-
- // Read the PES packet.
- DVLOG(LOG_LEVEL_PES)
- << "Emit a reassembled PES:"
- << " size=" << es_size
- << " pts=" << media_pts.InMilliseconds()
- << " dts=" << media_dts.InMilliseconds()
- << " data_alignment_indicator=" << data_alignment_indicator;
- return es_parser_->Parse(&raw_pes[es_offset], es_size, media_pts, media_dts);
-}
-
-void TsSectionPes::ResetPesState() {
- pes_byte_queue_.Reset();
- wait_for_pusi_ = true;
-}
-
-} // namespace mp2t
-} // namespace media
-
diff --git a/media/mp2t/ts_section_pes.h b/media/mp2t/ts_section_pes.h
deleted file mode 100644
index b80473a..0000000
--- a/media/mp2t/ts_section_pes.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 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.
-
-#ifndef MEDIA_MP2T_TS_SECTION_PES_H_
-#define MEDIA_MP2T_TS_SECTION_PES_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "media/base/byte_queue.h"
-#include "media/mp2t/ts_section.h"
-
-namespace media {
-namespace mp2t {
-
-class EsParser;
-
-class TsSectionPes : public TsSection {
- public:
- explicit TsSectionPes(scoped_ptr<EsParser> es_parser);
- virtual ~TsSectionPes();
-
- // TsSection implementation.
- virtual bool Parse(bool payload_unit_start_indicator,
- const uint8* buf, int size) OVERRIDE;
- virtual void Flush() OVERRIDE;
- virtual void Reset() OVERRIDE;
-
- private:
- // Emit a reassembled PES packet.
- // Return true if successful.
- // |emit_for_unknown_size| is used to force emission for PES packets
- // whose size is unknown.
- bool Emit(bool emit_for_unknown_size);
-
- // Parse a PES packet, return true if successful.
- bool ParseInternal(const uint8* raw_pes, int raw_pes_size);
-
- void ResetPesState();
-
- // Bytes of the current PES.
- ByteQueue pes_byte_queue_;
-
- // ES parser.
- scoped_ptr<EsParser> es_parser_;
-
- // Do not start parsing before getting a unit start indicator.
- bool wait_for_pusi_;
-
- // Used to unroll PTS and DTS.
- bool previous_pts_valid_;
- int64 previous_pts_;
- bool previous_dts_valid_;
- int64 previous_dts_;
-
- DISALLOW_COPY_AND_ASSIGN(TsSectionPes);
-};
-
-} // namespace mp2t
-} // namespace media
-
-#endif
-
diff --git a/media/mp2t/ts_section_pmt.cc b/media/mp2t/ts_section_pmt.cc
deleted file mode 100644
index 46fa202..0000000
--- a/media/mp2t/ts_section_pmt.cc
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright 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_section_pmt.h"
-
-#include <map>
-
-#include "base/logging.h"
-#include "media/base/bit_reader.h"
-#include "media/mp2t/mp2t_common.h"
-
-namespace media {
-namespace mp2t {
-
-TsSectionPmt::TsSectionPmt(const RegisterPesCb& register_pes_cb)
- : register_pes_cb_(register_pes_cb) {
-}
-
-TsSectionPmt::~TsSectionPmt() {
-}
-
-bool TsSectionPmt::ParsePsiSection(BitReader* bit_reader) {
- // Read up to |last_section_number|.
- int table_id;
- bool section_syntax_indicator;
- bool dummy_zero;
- int reserved;
- int section_length;
- int program_number;
- int version_number;
- bool current_next_indicator;
- int section_number;
- int last_section_number;
- RCHECK(bit_reader->ReadBits(8, &table_id));
- RCHECK(bit_reader->ReadBits(1, &section_syntax_indicator));
- RCHECK(bit_reader->ReadBits(1, &dummy_zero));
- RCHECK(bit_reader->ReadBits(2, &reserved));
- RCHECK(bit_reader->ReadBits(12, &section_length));
- int section_start_marker = bit_reader->bits_available() / 8;
-
- RCHECK(bit_reader->ReadBits(16, &program_number));
- RCHECK(bit_reader->ReadBits(2, &reserved));
- RCHECK(bit_reader->ReadBits(5, &version_number));
- RCHECK(bit_reader->ReadBits(1, &current_next_indicator));
- RCHECK(bit_reader->ReadBits(8, &section_number));
- RCHECK(bit_reader->ReadBits(8, &last_section_number));
-
- // Perform a few verifications:
- // - table ID should be 2 for a PMT.
- // - section_syntax_indicator should be one.
- // - section length should not exceed 1021.
- RCHECK(table_id == 0x2);
- RCHECK(section_syntax_indicator);
- RCHECK(!dummy_zero);
- RCHECK(section_length <= 1021);
- RCHECK(section_number == 0);
- RCHECK(last_section_number == 0);
-
- // TODO(damienv):
- // Verify that there is no mismatch between the program number
- // and the program number that was provided in a PAT for the current PMT.
-
- // Read the end of the fixed length section.
- int pcr_pid;
- int program_info_length;
- RCHECK(bit_reader->ReadBits(3, &reserved));
- RCHECK(bit_reader->ReadBits(13, &pcr_pid));
- RCHECK(bit_reader->ReadBits(4, &reserved));
- RCHECK(bit_reader->ReadBits(12, &program_info_length));
- RCHECK(program_info_length < 1024);
-
- // Read the program info descriptor.
- // TODO(damienv): check wether any of the descriptors could be useful.
- // Defined in section 2.6 of ISO-13818.
- RCHECK(bit_reader->SkipBits(8 * program_info_length));
-
- // Read the ES description table.
- // The end of the PID map if 4 bytes away from the end of the section
- // (4 bytes = size of the CRC).
- int pid_map_end_marker = section_start_marker - section_length + 4;
- std::map<int, int> pid_map;
- while (bit_reader->bits_available() > 8 * pid_map_end_marker) {
- int stream_type;
- int reserved;
- int pid_es;
- int es_info_length;
- RCHECK(bit_reader->ReadBits(8, &stream_type));
- RCHECK(bit_reader->ReadBits(3, &reserved));
- RCHECK(bit_reader->ReadBits(13, &pid_es));
- RCHECK(bit_reader->ReadBits(4, &reserved));
- RCHECK(bit_reader->ReadBits(12, &es_info_length));
-
- // Do not register the PID right away.
- // Wait for the end of the section to be fully parsed
- // to make sure there is no error.
- pid_map.insert(std::pair<int, int>(pid_es, stream_type));
-
- // Read the ES info descriptors.
- // TODO(damienv): check wether any of the descriptors could be useful.
- // Defined in section 2.6 of ISO-13818.
- RCHECK(bit_reader->SkipBits(8 * es_info_length));
- }
-
- // Read the CRC.
- int crc32;
- RCHECK(bit_reader->ReadBits(32, &crc32));
-
- // Once the PMT has been proved to be correct, register the PIDs.
- for (std::map<int, int>::iterator it = pid_map.begin();
- it != pid_map.end(); ++it)
- register_pes_cb_.Run(it->first, it->second);
-
- return true;
-}
-
-void TsSectionPmt::ResetPsiSection() {
-}
-
-} // namespace mp2t
-} // namespace media
-
diff --git a/media/mp2t/ts_section_pmt.h b/media/mp2t/ts_section_pmt.h
deleted file mode 100644
index ece4d16..0000000
--- a/media/mp2t/ts_section_pmt.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 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.
-
-#ifndef MEDIA_MP2T_TS_SECTION_PMT_H_
-#define MEDIA_MP2T_TS_SECTION_PMT_H_
-
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "media/mp2t/ts_section_psi.h"
-
-namespace media {
-namespace mp2t {
-
-class TsSectionPmt : public TsSectionPsi {
- public:
- // RegisterPesCb::Run(int pes_pid, int stream_type);
- // Stream type is defined in
- // "Table 2-34 – Stream type assignments" in H.222
- // TODO(damienv): add the program number.
- typedef base::Callback<void(int, int)> RegisterPesCb;
-
- explicit TsSectionPmt(const RegisterPesCb& register_pes_cb);
- virtual ~TsSectionPmt();
-
- // Mpeg2TsPsiParser implementation.
- virtual bool ParsePsiSection(BitReader* bit_reader) OVERRIDE;
- virtual void ResetPsiSection() OVERRIDE;
-
- private:
- RegisterPesCb register_pes_cb_;
-
- DISALLOW_COPY_AND_ASSIGN(TsSectionPmt);
-};
-
-} // namespace mp2t
-} // namespace media
-
-#endif
-
diff --git a/media/mp2t/ts_section_psi.cc b/media/mp2t/ts_section_psi.cc
deleted file mode 100644
index 43b27a1..0000000
--- a/media/mp2t/ts_section_psi.cc
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright 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_section_psi.h"
-
-#include "base/logging.h"
-#include "media/base/bit_reader.h"
-#include "media/mp2t/mp2t_common.h"
-
-static bool IsCrcValid(const uint8* buf, int size) {
- uint32 crc = 0xffffffffu;
- const uint32_t kCrcPoly = 0x4c11db7;
-
- for (int k = 0; k < size; k++) {
- int nbits = 8;
- uint32 data_msb_aligned = buf[k];
- data_msb_aligned <<= (32 - nbits);
-
- while (nbits > 0) {
- if ((data_msb_aligned ^ crc) & 0x80000000) {
- crc <<= 1;
- crc ^= kCrcPoly;
- } else {
- crc <<= 1;
- }
-
- data_msb_aligned <<= 1;
- nbits--;
- }
- }
-
- return (crc == 0);
-}
-
-namespace media {
-namespace mp2t {
-
-TsSectionPsi::TsSectionPsi()
- : wait_for_pusi_(true),
- leading_bytes_to_discard_(0) {
-}
-
-TsSectionPsi::~TsSectionPsi() {
-}
-
-bool TsSectionPsi::Parse(bool payload_unit_start_indicator,
- const uint8* buf, int size) {
- // Ignore partial PSI.
- if (wait_for_pusi_ && !payload_unit_start_indicator)
- return true;
-
- if (payload_unit_start_indicator) {
- // Reset the state of the PSI section.
- ResetPsiState();
-
- // Update the state.
- wait_for_pusi_ = false;
- DCHECK_GE(size, 1);
- int pointer_field = buf[0];
- leading_bytes_to_discard_ = pointer_field;
- buf++;
- size--;
- }
-
- // Discard some leading bytes if needed.
- if (leading_bytes_to_discard_ > 0) {
- int nbytes_to_discard = std::min(leading_bytes_to_discard_, size);
- buf += nbytes_to_discard;
- size -= nbytes_to_discard;
- leading_bytes_to_discard_ -= nbytes_to_discard;
- }
- if (size == 0)
- return true;
-
- // Add the data to the parser state.
- psi_byte_queue_.Push(buf, size);
- int raw_psi_size;
- const uint8* raw_psi;
- psi_byte_queue_.Peek(&raw_psi, &raw_psi_size);
-
- // Check whether we have enough data to start parsing.
- if (raw_psi_size < 3)
- return true;
- int section_length =
- ((static_cast<int>(raw_psi[1]) << 8) |
- (static_cast<int>(raw_psi[2]))) & 0xfff;
- if (section_length >= 1021)
- return false;
- int psi_length = section_length + 3;
- if (raw_psi_size < psi_length) {
- // Don't throw an error when there is not enough data,
- // just wait for more data to come.
- return true;
- }
-
- // There should not be any trailing bytes after a PMT.
- // Instead, the pointer field should be used to stuff bytes.
- DVLOG_IF(1, raw_psi_size > psi_length)
- << "Trailing bytes after a PSI section: "
- << psi_length << " vs " << raw_psi_size;
-
- // Verify the CRC.
- RCHECK(IsCrcValid(raw_psi, psi_length));
-
- // Parse the PSI section.
- BitReader bit_reader(raw_psi, raw_psi_size);
- bool status = ParsePsiSection(&bit_reader);
- if (status)
- ResetPsiState();
-
- return status;
-}
-
-void TsSectionPsi::Flush() {
-}
-
-void TsSectionPsi::Reset() {
- ResetPsiSection();
- ResetPsiState();
-}
-
-void TsSectionPsi::ResetPsiState() {
- wait_for_pusi_ = true;
- psi_byte_queue_.Reset();
- leading_bytes_to_discard_ = 0;
-}
-
-} // namespace mp2t
-} // namespace media
-
diff --git a/media/mp2t/ts_section_psi.h b/media/mp2t/ts_section_psi.h
deleted file mode 100644
index a631446..0000000
--- a/media/mp2t/ts_section_psi.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 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.
-
-#ifndef MEDIA_MP2T_TS_SECTION_PSI_H_
-#define MEDIA_MP2T_TS_SECTION_PSI_H_
-
-#include "base/compiler_specific.h"
-#include "media/base/byte_queue.h"
-#include "media/mp2t/ts_section.h"
-
-namespace media {
-
-class BitReader;
-
-namespace mp2t {
-
-class TsSectionPsi : public TsSection {
- public:
- TsSectionPsi();
- virtual ~TsSectionPsi();
-
- // TsSection implementation.
- virtual bool Parse(bool payload_unit_start_indicator,
- const uint8* buf, int size) OVERRIDE;
- virtual void Flush() OVERRIDE;
- virtual void Reset() OVERRIDE;
-
- // Parse the content of the PSI section.
- virtual bool ParsePsiSection(BitReader* bit_reader) = 0;
-
- // Reset the state of the PSI section.
- virtual void ResetPsiSection() = 0;
-
- private:
- void ResetPsiState();
-
- // Bytes of the current PSI.
- ByteQueue psi_byte_queue_;
-
- // Do not start parsing before getting a unit start indicator.
- bool wait_for_pusi_;
-
- // Number of leading bytes to discard (pointer field).
- int leading_bytes_to_discard_;
-
- DISALLOW_COPY_AND_ASSIGN(TsSectionPsi);
-};
-
-} // namespace mp2t
-} // namespace media
-
-#endif
-