| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/filters/chunk_demuxer.h" | 5 #include "media/filters/chunk_demuxer.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <deque> | 8 #include <deque> |
| 9 #include <limits> | 9 #include <limits> |
| 10 | 10 |
| 11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "base/callback_helpers.h" | 12 #include "base/callback_helpers.h" |
| 13 #include "base/location.h" | 13 #include "base/location.h" |
| 14 #include "base/message_loop_proxy.h" | 14 #include "base/message_loop_proxy.h" |
| 15 #include "media/base/audio_decoder_config.h" | 15 #include "media/base/audio_decoder_config.h" |
| 16 #include "media/base/stream_parser_buffer.h" | 16 #include "media/base/stream_parser_buffer.h" |
| 17 #include "media/base/video_decoder_config.h" | 17 #include "media/base/video_decoder_config.h" |
| 18 #include "media/filters/stream_parser_factory.h" | 18 #include "media/filters/stream_parser_factory.h" |
| 19 #include "media/webm/webm_webvtt_parser.h" |
| 19 | 20 |
| 20 using base::TimeDelta; | 21 using base::TimeDelta; |
| 21 | 22 |
| 22 namespace media { | 23 namespace media { |
| 23 | 24 |
| 24 // Contains state belonging to a source id. | 25 // Contains state belonging to a source id. |
| 25 class SourceState { | 26 class SourceState { |
| 26 public: | 27 public: |
| 27 explicit SourceState(scoped_ptr<StreamParser> stream_parser); | 28 explicit SourceState(scoped_ptr<StreamParser> stream_parser); |
| 28 | 29 |
| 29 void Init(const StreamParser::InitCB& init_cb, | 30 void Init(const StreamParser::InitCB& init_cb, |
| 30 const StreamParser::NewConfigCB& config_cb, | 31 const StreamParser::NewConfigCB& config_cb, |
| 31 const StreamParser::NewBuffersCB& audio_cb, | 32 const StreamParser::NewBuffersCB& audio_cb, |
| 32 const StreamParser::NewBuffersCB& video_cb, | 33 const StreamParser::NewBuffersCB& video_cb, |
| 34 const StreamParser::NewTextBuffersCB& text_cb, |
| 33 const StreamParser::NeedKeyCB& need_key_cb, | 35 const StreamParser::NeedKeyCB& need_key_cb, |
| 36 const AddTextTrackCB& add_text_track_cb, |
| 34 const StreamParser::NewMediaSegmentCB& new_segment_cb, | 37 const StreamParser::NewMediaSegmentCB& new_segment_cb, |
| 35 const LogCB& log_cb); | 38 const LogCB& log_cb); |
| 36 | 39 |
| 37 // Appends new data to the StreamParser. | 40 // Appends new data to the StreamParser. |
| 38 // Returns true if the data was successfully appended. Returns false if an | 41 // Returns true if the data was successfully appended. Returns false if an |
| 39 // error occurred. | 42 // error occurred. |
| 40 bool Append(const uint8* data, size_t length); | 43 bool Append(const uint8* data, size_t length); |
| 41 | 44 |
| 42 // Aborts the current append sequence and resets the parser. | 45 // Aborts the current append sequence and resets the parser. |
| 43 void Abort(); | 46 void Abort(); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 61 void OnEndOfMediaSegment(); | 64 void OnEndOfMediaSegment(); |
| 62 | 65 |
| 63 // Called by the |stream_parser_| when new buffers have been parsed. It | 66 // Called by the |stream_parser_| when new buffers have been parsed. It |
| 64 // applies |timestamp_offset_| to all buffers in |buffers| and then calls | 67 // applies |timestamp_offset_| to all buffers in |buffers| and then calls |
| 65 // |new_buffers_cb| with the modified buffers. | 68 // |new_buffers_cb| with the modified buffers. |
| 66 // Returns true on a successful call. Returns false if an error occured while | 69 // Returns true on a successful call. Returns false if an error occured while |
| 67 // processing the buffers. | 70 // processing the buffers. |
| 68 bool OnBuffers(const StreamParser::NewBuffersCB& new_buffers_cb, | 71 bool OnBuffers(const StreamParser::NewBuffersCB& new_buffers_cb, |
| 69 const StreamParser::BufferQueue& buffers); | 72 const StreamParser::BufferQueue& buffers); |
| 70 | 73 |
| 74 // Called by the |stream_parser_| when new text buffers have been parsed. It |
| 75 // applies |timestamp_offset_| to all buffers in |buffers| and then calls |
| 76 // |new_buffers_cb| with the modified buffers. |
| 77 // Returns true on a successful call. Returns false if an error occured while |
| 78 // processing the buffers. |
| 79 bool OnTextBuffers(const StreamParser::NewTextBuffersCB& new_buffers_cb, |
| 80 TextTrack* text_track, |
| 81 const StreamParser::BufferQueue& buffers); |
| 82 |
| 71 // Helper function that adds |timestamp_offset_| to each buffer in |buffers|. | 83 // Helper function that adds |timestamp_offset_| to each buffer in |buffers|. |
| 72 void AdjustBufferTimestamps(const StreamParser::BufferQueue& buffers); | 84 void AdjustBufferTimestamps(const StreamParser::BufferQueue& buffers); |
| 73 | 85 |
| 74 // The offset to apply to media segment timestamps. | 86 // The offset to apply to media segment timestamps. |
| 75 TimeDelta timestamp_offset_; | 87 TimeDelta timestamp_offset_; |
| 76 | 88 |
| 77 // Keeps track of whether |timestamp_offset_| can be modified. | 89 // Keeps track of whether |timestamp_offset_| can be modified. |
| 78 bool can_update_offset_; | 90 bool can_update_offset_; |
| 79 | 91 |
| 80 // The object used to parse appended data. | 92 // The object used to parse appended data. |
| 81 scoped_ptr<StreamParser> stream_parser_; | 93 scoped_ptr<StreamParser> stream_parser_; |
| 82 | 94 |
| 83 DISALLOW_COPY_AND_ASSIGN(SourceState); | 95 DISALLOW_COPY_AND_ASSIGN(SourceState); |
| 84 }; | 96 }; |
| 85 | 97 |
| 86 SourceState::SourceState(scoped_ptr<StreamParser> stream_parser) | 98 SourceState::SourceState(scoped_ptr<StreamParser> stream_parser) |
| 87 : can_update_offset_(true), | 99 : can_update_offset_(true), |
| 88 stream_parser_(stream_parser.release()) { | 100 stream_parser_(stream_parser.release()) { |
| 89 } | 101 } |
| 90 | 102 |
| 91 void SourceState::Init(const StreamParser::InitCB& init_cb, | 103 void SourceState::Init(const StreamParser::InitCB& init_cb, |
| 92 const StreamParser::NewConfigCB& config_cb, | 104 const StreamParser::NewConfigCB& config_cb, |
| 93 const StreamParser::NewBuffersCB& audio_cb, | 105 const StreamParser::NewBuffersCB& audio_cb, |
| 94 const StreamParser::NewBuffersCB& video_cb, | 106 const StreamParser::NewBuffersCB& video_cb, |
| 107 const StreamParser::NewTextBuffersCB& text_cb, |
| 95 const StreamParser::NeedKeyCB& need_key_cb, | 108 const StreamParser::NeedKeyCB& need_key_cb, |
| 109 const AddTextTrackCB& add_text_track_cb, |
| 96 const StreamParser::NewMediaSegmentCB& new_segment_cb, | 110 const StreamParser::NewMediaSegmentCB& new_segment_cb, |
| 97 const LogCB& log_cb) { | 111 const LogCB& log_cb) { |
| 98 stream_parser_->Init(init_cb, config_cb, | 112 stream_parser_->Init(init_cb, config_cb, |
| 99 base::Bind(&SourceState::OnBuffers, | 113 base::Bind(&SourceState::OnBuffers, |
| 100 base::Unretained(this), audio_cb), | 114 base::Unretained(this), audio_cb), |
| 101 base::Bind(&SourceState::OnBuffers, | 115 base::Bind(&SourceState::OnBuffers, |
| 102 base::Unretained(this), video_cb), | 116 base::Unretained(this), video_cb), |
| 117 base::Bind(&SourceState::OnTextBuffers, |
| 118 base::Unretained(this), text_cb), |
| 103 need_key_cb, | 119 need_key_cb, |
| 120 add_text_track_cb, |
| 104 base::Bind(&SourceState::OnNewMediaSegment, | 121 base::Bind(&SourceState::OnNewMediaSegment, |
| 105 base::Unretained(this), new_segment_cb), | 122 base::Unretained(this), new_segment_cb), |
| 106 base::Bind(&SourceState::OnEndOfMediaSegment, | 123 base::Bind(&SourceState::OnEndOfMediaSegment, |
| 107 base::Unretained(this)), | 124 base::Unretained(this)), |
| 108 log_cb); | 125 log_cb); |
| 109 } | 126 } |
| 110 | 127 |
| 111 bool SourceState::SetTimestampOffset(TimeDelta timestamp_offset) { | 128 bool SourceState::SetTimestampOffset(TimeDelta timestamp_offset) { |
| 112 if (!can_update_offset_) | 129 if (!can_update_offset_) |
| 113 return false; | 130 return false; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 156 bool SourceState::OnBuffers(const StreamParser::NewBuffersCB& new_buffers_cb, | 173 bool SourceState::OnBuffers(const StreamParser::NewBuffersCB& new_buffers_cb, |
| 157 const StreamParser::BufferQueue& buffers) { | 174 const StreamParser::BufferQueue& buffers) { |
| 158 if (new_buffers_cb.is_null()) | 175 if (new_buffers_cb.is_null()) |
| 159 return false; | 176 return false; |
| 160 | 177 |
| 161 AdjustBufferTimestamps(buffers); | 178 AdjustBufferTimestamps(buffers); |
| 162 | 179 |
| 163 return new_buffers_cb.Run(buffers); | 180 return new_buffers_cb.Run(buffers); |
| 164 } | 181 } |
| 165 | 182 |
| 183 bool SourceState::OnTextBuffers( |
| 184 const StreamParser::NewTextBuffersCB& new_buffers_cb, |
| 185 TextTrack* text_track, |
| 186 const StreamParser::BufferQueue& buffers) { |
| 187 if (new_buffers_cb.is_null()) |
| 188 return false; |
| 189 |
| 190 AdjustBufferTimestamps(buffers); |
| 191 |
| 192 return new_buffers_cb.Run(text_track, buffers); |
| 193 } |
| 194 |
| 166 class ChunkDemuxerStream : public DemuxerStream { | 195 class ChunkDemuxerStream : public DemuxerStream { |
| 167 public: | 196 public: |
| 168 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; | 197 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; |
| 169 typedef std::deque<ReadCB> ReadCBQueue; | 198 typedef std::deque<ReadCB> ReadCBQueue; |
| 170 typedef std::deque<base::Closure> ClosureQueue; | 199 typedef std::deque<base::Closure> ClosureQueue; |
| 171 | 200 |
| 172 ChunkDemuxerStream(const AudioDecoderConfig& audio_config, | 201 ChunkDemuxerStream(const AudioDecoderConfig& audio_config, |
| 173 const LogCB& log_cb); | 202 const LogCB& log_cb); |
| 174 ChunkDemuxerStream(const VideoDecoderConfig& video_config, | 203 ChunkDemuxerStream(const VideoDecoderConfig& video_config, |
| 175 const LogCB& log_cb); | 204 const LogCB& log_cb); |
| (...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 538 *buffer = StreamParserBuffer::CreateEOSBuffer(); | 567 *buffer = StreamParserBuffer::CreateEOSBuffer(); |
| 539 return true; | 568 return true; |
| 540 } | 569 } |
| 541 | 570 |
| 542 NOTREACHED(); | 571 NOTREACHED(); |
| 543 return false; | 572 return false; |
| 544 } | 573 } |
| 545 | 574 |
| 546 ChunkDemuxer::ChunkDemuxer(const base::Closure& open_cb, | 575 ChunkDemuxer::ChunkDemuxer(const base::Closure& open_cb, |
| 547 const NeedKeyCB& need_key_cb, | 576 const NeedKeyCB& need_key_cb, |
| 577 const AddTextTrackCB& add_text_track_cb, |
| 548 const LogCB& log_cb) | 578 const LogCB& log_cb) |
| 549 : state_(WAITING_FOR_INIT), | 579 : state_(WAITING_FOR_INIT), |
| 550 host_(NULL), | 580 host_(NULL), |
| 551 open_cb_(open_cb), | 581 open_cb_(open_cb), |
| 552 need_key_cb_(need_key_cb), | 582 need_key_cb_(need_key_cb), |
| 583 add_text_track_cb_(add_text_track_cb), |
| 553 log_cb_(log_cb), | 584 log_cb_(log_cb), |
| 554 duration_(kNoTimestamp()), | 585 duration_(kNoTimestamp()), |
| 555 user_specified_duration_(-1) { | 586 user_specified_duration_(-1) { |
| 556 DCHECK(!open_cb_.is_null()); | 587 DCHECK(!open_cb_.is_null()); |
| 557 DCHECK(!need_key_cb_.is_null()); | 588 DCHECK(!need_key_cb_.is_null()); |
| 558 } | 589 } |
| 559 | 590 |
| 560 void ChunkDemuxer::Initialize(DemuxerHost* host, const PipelineStatusCB& cb) { | 591 void ChunkDemuxer::Initialize(DemuxerHost* host, const PipelineStatusCB& cb) { |
| 561 DVLOG(1) << "Init()"; | 592 DVLOG(1) << "Init()"; |
| 562 | 593 |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 703 base::Unretained(this)); | 734 base::Unretained(this)); |
| 704 } | 735 } |
| 705 | 736 |
| 706 scoped_ptr<SourceState> source_state(new SourceState(stream_parser.Pass())); | 737 scoped_ptr<SourceState> source_state(new SourceState(stream_parser.Pass())); |
| 707 source_state->Init( | 738 source_state->Init( |
| 708 base::Bind(&ChunkDemuxer::OnSourceInitDone, base::Unretained(this)), | 739 base::Bind(&ChunkDemuxer::OnSourceInitDone, base::Unretained(this)), |
| 709 base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this), | 740 base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this), |
| 710 has_audio, has_video), | 741 has_audio, has_video), |
| 711 audio_cb, | 742 audio_cb, |
| 712 video_cb, | 743 video_cb, |
| 744 base::Bind(&ChunkDemuxer::OnTextBuffers, base::Unretained(this)), |
| 713 base::Bind(&ChunkDemuxer::OnNeedKey, base::Unretained(this)), | 745 base::Bind(&ChunkDemuxer::OnNeedKey, base::Unretained(this)), |
| 746 add_text_track_cb_, |
| 714 base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id), | 747 base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id), |
| 715 log_cb_); | 748 log_cb_); |
| 716 | 749 |
| 717 source_state_map_[id] = source_state.release(); | 750 source_state_map_[id] = source_state.release(); |
| 718 return kOk; | 751 return kOk; |
| 719 } | 752 } |
| 720 | 753 |
| 721 void ChunkDemuxer::RemoveId(const std::string& id) { | 754 void ChunkDemuxer::RemoveId(const std::string& id) { |
| 722 base::AutoLock auto_lock(lock_); | 755 base::AutoLock auto_lock(lock_); |
| 723 CHECK(IsValidId(id)); | 756 CHECK(IsValidId(id)); |
| (...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1179 return false; | 1212 return false; |
| 1180 | 1213 |
| 1181 CHECK(IsValidId(source_id_video_)); | 1214 CHECK(IsValidId(source_id_video_)); |
| 1182 if (!video_->Append(buffers)) | 1215 if (!video_->Append(buffers)) |
| 1183 return false; | 1216 return false; |
| 1184 | 1217 |
| 1185 IncreaseDurationIfNecessary(buffers, video_.get()); | 1218 IncreaseDurationIfNecessary(buffers, video_.get()); |
| 1186 return true; | 1219 return true; |
| 1187 } | 1220 } |
| 1188 | 1221 |
| 1222 bool ChunkDemuxer::OnTextBuffers( |
| 1223 TextTrack* text_track, |
| 1224 const StreamParser::BufferQueue& buffers) { |
| 1225 lock_.AssertAcquired(); |
| 1226 DCHECK_NE(state_, SHUTDOWN); |
| 1227 |
| 1228 // TODO(matthewjheaney): IncreaseDurationIfNecessary |
| 1229 |
| 1230 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); |
| 1231 itr != buffers.end(); ++itr) { |
| 1232 const StreamParserBuffer* const buffer = itr->get(); |
| 1233 const base::TimeDelta start = buffer->GetTimestamp(); |
| 1234 const base::TimeDelta end = start + buffer->GetDuration(); |
| 1235 |
| 1236 std::string id, settings, content; |
| 1237 |
| 1238 WebMWebVTTParser::Parse(buffer->GetData(), |
| 1239 buffer->GetDataSize(), |
| 1240 &id, &settings, &content); |
| 1241 |
| 1242 text_track->addWebVTTCue(start, end, id, content, settings); |
| 1243 } |
| 1244 |
| 1245 return true; |
| 1246 } |
| 1247 |
| 1189 // TODO(acolwell): Remove bool from StreamParser::NeedKeyCB so that | 1248 // TODO(acolwell): Remove bool from StreamParser::NeedKeyCB so that |
| 1190 // this method can be removed and need_key_cb_ can be passed directly | 1249 // this method can be removed and need_key_cb_ can be passed directly |
| 1191 // to the parser. | 1250 // to the parser. |
| 1192 bool ChunkDemuxer::OnNeedKey(const std::string& type, | 1251 bool ChunkDemuxer::OnNeedKey(const std::string& type, |
| 1193 scoped_ptr<uint8[]> init_data, | 1252 scoped_ptr<uint8[]> init_data, |
| 1194 int init_data_size) { | 1253 int init_data_size) { |
| 1195 lock_.AssertAcquired(); | 1254 lock_.AssertAcquired(); |
| 1196 need_key_cb_.Run(type, init_data.Pass(), init_data_size); | 1255 need_key_cb_.Run(type, init_data.Pass(), init_data_size); |
| 1197 return true; | 1256 return true; |
| 1198 } | 1257 } |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1250 | 1309 |
| 1251 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges() const { | 1310 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges() const { |
| 1252 if (audio_ && !video_) | 1311 if (audio_ && !video_) |
| 1253 return audio_->GetBufferedRanges(duration_); | 1312 return audio_->GetBufferedRanges(duration_); |
| 1254 else if (!audio_ && video_) | 1313 else if (!audio_ && video_) |
| 1255 return video_->GetBufferedRanges(duration_); | 1314 return video_->GetBufferedRanges(duration_); |
| 1256 return ComputeIntersection(); | 1315 return ComputeIntersection(); |
| 1257 } | 1316 } |
| 1258 | 1317 |
| 1259 } // namespace media | 1318 } // namespace media |
| OLD | NEW |