diff options
Diffstat (limited to 'media/mp2t')
-rw-r--r-- | media/mp2t/es_parser.h | 42 | ||||
-rw-r--r-- | media/mp2t/es_parser_adts.cc | 295 | ||||
-rw-r--r-- | media/mp2t/es_parser_adts.h | 81 | ||||
-rw-r--r-- | media/mp2t/es_parser_h264.cc | 507 | ||||
-rw-r--r-- | media/mp2t/es_parser_h264.h | 97 | ||||
-rw-r--r-- | media/mp2t/mp2t_common.h | 21 | ||||
-rw-r--r-- | media/mp2t/mp2t_stream_parser.cc | 616 | ||||
-rw-r--r-- | media/mp2t/mp2t_stream_parser.h | 133 | ||||
-rw-r--r-- | media/mp2t/mp2t_stream_parser_unittest.cc | 189 | ||||
-rw-r--r-- | media/mp2t/ts_packet.cc | 209 | ||||
-rw-r--r-- | media/mp2t/ts_packet.h | 73 | ||||
-rw-r--r-- | media/mp2t/ts_section.h | 40 | ||||
-rw-r--r-- | media/mp2t/ts_section_pat.cc | 122 | ||||
-rw-r--r-- | media/mp2t/ts_section_pat.h | 40 | ||||
-rw-r--r-- | media/mp2t/ts_section_pes.cc | 312 | ||||
-rw-r--r-- | media/mp2t/ts_section_pes.h | 64 | ||||
-rw-r--r-- | media/mp2t/ts_section_pmt.cc | 122 | ||||
-rw-r--r-- | media/mp2t/ts_section_pmt.h | 40 | ||||
-rw-r--r-- | media/mp2t/ts_section_psi.cc | 131 | ||||
-rw-r--r-- | media/mp2t/ts_section_psi.h | 54 |
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, §ion_syntax_indicator)); - RCHECK(bit_reader->ReadBits(1, &dummy_zero)); - RCHECK(bit_reader->ReadBits(2, &reserved)); - RCHECK(bit_reader->ReadBits(12, §ion_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, ¤t_next_indicator)); - RCHECK(bit_reader->ReadBits(8, §ion_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, ©right)); - 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, §ion_syntax_indicator)); - RCHECK(bit_reader->ReadBits(1, &dummy_zero)); - RCHECK(bit_reader->ReadBits(2, &reserved)); - RCHECK(bit_reader->ReadBits(12, §ion_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, ¤t_next_indicator)); - RCHECK(bit_reader->ReadBits(8, §ion_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 - |