Chromium Code Reviews| 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 <limits> | 8 #include <limits> |
| 9 #include <list> | 9 #include <list> |
| 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/message_loop_proxy.h" | 14 #include "base/message_loop/message_loop_proxy.h" |
| 15 #include "base/stl_util.h" | 15 #include "base/stl_util.h" |
| 16 #include "media/base/audio_decoder_config.h" | 16 #include "media/base/audio_decoder_config.h" |
| 17 #include "media/base/bind_to_current_loop.h" | 17 #include "media/base/bind_to_current_loop.h" |
| 18 #include "media/base/stream_parser_buffer.h" | 18 #include "media/base/stream_parser_buffer.h" |
| 19 #include "media/base/video_decoder_config.h" | 19 #include "media/base/video_decoder_config.h" |
| 20 #include "media/filters/legacy_frame_processor.h" | 20 #include "media/filters/legacy_frame_processor.h" |
| 21 #include "media/filters/stream_parser_factory.h" | 21 #include "media/filters/stream_parser_factory.h" |
| 22 | 22 |
| 23 using base::TimeDelta; | 23 using base::TimeDelta; |
| 24 | 24 |
| 25 namespace media { | 25 namespace media { |
| 26 | 26 |
| 27 static TimeDelta EndTimestamp(const StreamParser::BufferQueue& queue) { | |
| 28 return queue.back()->timestamp() + queue.back()->duration(); | |
| 29 } | |
| 30 | |
| 27 // List of time ranges for each SourceBuffer. | 31 // List of time ranges for each SourceBuffer. |
| 28 typedef std::list<Ranges<TimeDelta> > RangesList; | 32 typedef std::list<Ranges<TimeDelta> > RangesList; |
| 29 static Ranges<TimeDelta> ComputeIntersection(const RangesList& activeRanges, | 33 static Ranges<TimeDelta> ComputeIntersection(const RangesList& activeRanges, |
| 30 bool ended) { | 34 bool ended) { |
| 31 // Implementation of HTMLMediaElement.buffered algorithm in MSE spec. | 35 // Implementation of HTMLMediaElement.buffered algorithm in MSE spec. |
| 32 // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-sourc e.html#dom-htmlmediaelement.buffered | 36 // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-sourc e.html#dom-htmlmediaelement.buffered |
| 33 | 37 |
| 34 // Step 1: If activeSourceBuffers.length equals 0 then return an empty | 38 // Step 1: If activeSourceBuffers.length equals 0 then return an empty |
| 35 // TimeRanges object and abort these steps. | 39 // TimeRanges object and abort these steps. |
| 36 if (activeRanges.empty()) | 40 if (activeRanges.empty()) |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 82 // Contains state belonging to a source id. | 86 // Contains state belonging to a source id. |
| 83 class SourceState { | 87 class SourceState { |
| 84 public: | 88 public: |
| 85 // Callback signature used to create ChunkDemuxerStreams. | 89 // Callback signature used to create ChunkDemuxerStreams. |
| 86 typedef base::Callback<ChunkDemuxerStream*( | 90 typedef base::Callback<ChunkDemuxerStream*( |
| 87 DemuxerStream::Type)> CreateDemuxerStreamCB; | 91 DemuxerStream::Type)> CreateDemuxerStreamCB; |
| 88 | 92 |
| 89 typedef base::Callback<void( | 93 typedef base::Callback<void( |
| 90 ChunkDemuxerStream*, const TextTrackConfig&)> NewTextTrackCB; | 94 ChunkDemuxerStream*, const TextTrackConfig&)> NewTextTrackCB; |
| 91 | 95 |
| 96 // First parameter - Indicates initialization success. Set to true if | |
| 97 // initialization was successful. False if an error | |
| 98 // occurred. | |
| 99 // Second parameter - Indicates the stream duration. Only contains a valid | |
| 100 // value if the first parameter is true. | |
| 101 typedef base::Callback<void(bool, TimeDelta)> InitCB; | |
| 102 | |
| 92 SourceState( | 103 SourceState( |
| 93 scoped_ptr<StreamParser> stream_parser, | 104 scoped_ptr<StreamParser> stream_parser, |
| 94 scoped_ptr<FrameProcessorBase> frame_processor, const LogCB& log_cb, | 105 scoped_ptr<FrameProcessorBase> frame_processor, const LogCB& log_cb, |
| 95 const CreateDemuxerStreamCB& create_demuxer_stream_cb); | 106 const CreateDemuxerStreamCB& create_demuxer_stream_cb); |
| 96 | 107 |
| 97 ~SourceState(); | 108 ~SourceState(); |
| 98 | 109 |
| 99 void Init(const StreamParser::InitCB& init_cb, | 110 void Init(const InitCB& init_cb, |
| 100 bool allow_audio, | 111 bool allow_audio, |
| 101 bool allow_video, | 112 bool allow_video, |
| 102 const StreamParser::NeedKeyCB& need_key_cb, | 113 const StreamParser::NeedKeyCB& need_key_cb, |
| 103 const NewTextTrackCB& new_text_track_cb); | 114 const NewTextTrackCB& new_text_track_cb); |
| 104 | 115 |
| 105 // Appends new data to the StreamParser. | 116 // Appends new data to the StreamParser. |
| 106 // Returns true if the data was successfully appended. Returns false if an | 117 // Returns true if the data was successfully appended. Returns false if an |
| 107 // error occurred. |*timestamp_offset| is used and possibly updated by the | 118 // error occurred. |*timestamp_offset| is used and possibly updated by the |
| 108 // append. |append_window_start| and |append_window_end| correspond to the MSE | 119 // append. |append_window_start| and |append_window_end| correspond to the MSE |
| 109 // spec's similarly named source buffer attributes that are used in coded | 120 // spec's similarly named source buffer attributes that are used in coded |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 170 // Called by the |stream_parser_| when new buffers have been parsed. | 181 // Called by the |stream_parser_| when new buffers have been parsed. |
| 171 // It processes the new buffers using |frame_processor_|, which includes | 182 // It processes the new buffers using |frame_processor_|, which includes |
| 172 // appending the processed frames to associated demuxer streams for each | 183 // appending the processed frames to associated demuxer streams for each |
| 173 // frame's track. | 184 // frame's track. |
| 174 // Returns true on a successful call. Returns false if an error occurred while | 185 // Returns true on a successful call. Returns false if an error occurred while |
| 175 // processing the buffers. | 186 // processing the buffers. |
| 176 bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers, | 187 bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers, |
| 177 const StreamParser::BufferQueue& video_buffers, | 188 const StreamParser::BufferQueue& video_buffers, |
| 178 const StreamParser::TextBufferQueueMap& text_map); | 189 const StreamParser::TextBufferQueueMap& text_map); |
| 179 | 190 |
| 191 void OnSourceInitDone(bool success, | |
| 192 TimeDelta duration, | |
| 193 bool auto_update_timestamp_offset); | |
| 194 | |
| 180 CreateDemuxerStreamCB create_demuxer_stream_cb_; | 195 CreateDemuxerStreamCB create_demuxer_stream_cb_; |
| 181 NewTextTrackCB new_text_track_cb_; | 196 NewTextTrackCB new_text_track_cb_; |
| 182 | 197 |
| 183 // During Append(), if OnNewBuffers() coded frame processing updates the | 198 // During Append(), if OnNewBuffers() coded frame processing updates the |
| 184 // timestamp offset then |*timestamp_offset_during_append_| is also updated | 199 // timestamp offset then |*timestamp_offset_during_append_| is also updated |
| 185 // so Append()'s caller can know the new offset. This pointer is only non-NULL | 200 // so Append()'s caller can know the new offset. This pointer is only non-NULL |
| 186 // during the lifetime of an Append() call. | 201 // during the lifetime of an Append() call. |
| 187 TimeDelta* timestamp_offset_during_append_; | 202 TimeDelta* timestamp_offset_during_append_; |
| 188 | 203 |
| 189 // During Append(), coded frame processing triggered by OnNewBuffers() | 204 // During Append(), coded frame processing triggered by OnNewBuffers() |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 209 scoped_ptr<StreamParser> stream_parser_; | 224 scoped_ptr<StreamParser> stream_parser_; |
| 210 | 225 |
| 211 ChunkDemuxerStream* audio_; // Not owned by |this|. | 226 ChunkDemuxerStream* audio_; // Not owned by |this|. |
| 212 ChunkDemuxerStream* video_; // Not owned by |this|. | 227 ChunkDemuxerStream* video_; // Not owned by |this|. |
| 213 | 228 |
| 214 typedef std::map<StreamParser::TrackId, ChunkDemuxerStream*> TextStreamMap; | 229 typedef std::map<StreamParser::TrackId, ChunkDemuxerStream*> TextStreamMap; |
| 215 TextStreamMap text_stream_map_; // |this| owns the map's stream pointers. | 230 TextStreamMap text_stream_map_; // |this| owns the map's stream pointers. |
| 216 | 231 |
| 217 scoped_ptr<FrameProcessorBase> frame_processor_; | 232 scoped_ptr<FrameProcessorBase> frame_processor_; |
| 218 LogCB log_cb_; | 233 LogCB log_cb_; |
| 234 InitCB init_cb_; | |
| 235 | |
| 236 // Indicates that timestampOffset should be updated automatically during | |
| 237 // OnNewBuffers() based on the earliest end timestamp of the buffers provided. | |
| 238 bool auto_update_timestamp_offset_; | |
| 219 | 239 |
| 220 DISALLOW_COPY_AND_ASSIGN(SourceState); | 240 DISALLOW_COPY_AND_ASSIGN(SourceState); |
| 221 }; | 241 }; |
| 222 | 242 |
| 223 SourceState::SourceState( | 243 SourceState::SourceState(scoped_ptr<StreamParser> stream_parser, |
| 224 scoped_ptr<StreamParser> stream_parser, | 244 scoped_ptr<FrameProcessorBase> frame_processor, |
| 225 scoped_ptr<FrameProcessorBase> frame_processor, | 245 const LogCB& log_cb, |
| 226 const LogCB& log_cb, | 246 const CreateDemuxerStreamCB& create_demuxer_stream_cb) |
| 227 const CreateDemuxerStreamCB& create_demuxer_stream_cb) | |
| 228 : create_demuxer_stream_cb_(create_demuxer_stream_cb), | 247 : create_demuxer_stream_cb_(create_demuxer_stream_cb), |
| 229 timestamp_offset_during_append_(NULL), | 248 timestamp_offset_during_append_(NULL), |
| 230 new_media_segment_(false), | 249 new_media_segment_(false), |
| 231 parsing_media_segment_(false), | 250 parsing_media_segment_(false), |
| 232 stream_parser_(stream_parser.release()), | 251 stream_parser_(stream_parser.release()), |
| 233 audio_(NULL), | 252 audio_(NULL), |
| 234 video_(NULL), | 253 video_(NULL), |
| 235 frame_processor_(frame_processor.release()), | 254 frame_processor_(frame_processor.release()), |
| 236 log_cb_(log_cb) { | 255 log_cb_(log_cb), |
| 256 auto_update_timestamp_offset_(false) { | |
| 237 DCHECK(!create_demuxer_stream_cb_.is_null()); | 257 DCHECK(!create_demuxer_stream_cb_.is_null()); |
| 238 DCHECK(frame_processor_); | 258 DCHECK(frame_processor_); |
| 239 } | 259 } |
| 240 | 260 |
| 241 SourceState::~SourceState() { | 261 SourceState::~SourceState() { |
| 242 Shutdown(); | 262 Shutdown(); |
| 243 | 263 |
| 244 STLDeleteValues(&text_stream_map_); | 264 STLDeleteValues(&text_stream_map_); |
| 245 } | 265 } |
| 246 | 266 |
| 247 void SourceState::Init(const StreamParser::InitCB& init_cb, | 267 void SourceState::Init(const InitCB& init_cb, |
| 248 bool allow_audio, | 268 bool allow_audio, |
| 249 bool allow_video, | 269 bool allow_video, |
| 250 const StreamParser::NeedKeyCB& need_key_cb, | 270 const StreamParser::NeedKeyCB& need_key_cb, |
| 251 const NewTextTrackCB& new_text_track_cb) { | 271 const NewTextTrackCB& new_text_track_cb) { |
| 252 new_text_track_cb_ = new_text_track_cb; | 272 new_text_track_cb_ = new_text_track_cb; |
| 273 init_cb_ = init_cb; | |
| 253 | 274 |
| 254 stream_parser_->Init(init_cb, | 275 stream_parser_->Init( |
| 255 base::Bind(&SourceState::OnNewConfigs, | 276 base::Bind(&SourceState::OnSourceInitDone, base::Unretained(this)), |
| 256 base::Unretained(this), | 277 base::Bind(&SourceState::OnNewConfigs, |
| 257 allow_audio, | 278 base::Unretained(this), |
| 258 allow_video), | 279 allow_audio, |
| 259 base::Bind(&SourceState::OnNewBuffers, | 280 allow_video), |
| 260 base::Unretained(this)), | 281 base::Bind(&SourceState::OnNewBuffers, base::Unretained(this)), |
| 261 new_text_track_cb_.is_null(), | 282 new_text_track_cb_.is_null(), |
| 262 need_key_cb, | 283 need_key_cb, |
| 263 base::Bind(&SourceState::OnNewMediaSegment, | 284 base::Bind(&SourceState::OnNewMediaSegment, base::Unretained(this)), |
| 264 base::Unretained(this)), | 285 base::Bind(&SourceState::OnEndOfMediaSegment, base::Unretained(this)), |
| 265 base::Bind(&SourceState::OnEndOfMediaSegment, | 286 log_cb_); |
| 266 base::Unretained(this)), | |
| 267 log_cb_); | |
| 268 } | 287 } |
| 269 | 288 |
| 270 void SourceState::SetSequenceMode(bool sequence_mode) { | 289 void SourceState::SetSequenceMode(bool sequence_mode) { |
| 271 DCHECK(!parsing_media_segment_); | 290 DCHECK(!parsing_media_segment_); |
| 272 | 291 |
| 273 frame_processor_->SetSequenceMode(sequence_mode); | 292 frame_processor_->SetSequenceMode(sequence_mode); |
| 274 } | 293 } |
| 275 | 294 |
| 276 bool SourceState::Append(const uint8* data, size_t length, | 295 bool SourceState::Append(const uint8* data, size_t length, |
| 277 TimeDelta append_window_start, | 296 TimeDelta append_window_start, |
| (...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 631 new_media_segment_ = false; | 650 new_media_segment_ = false; |
| 632 } | 651 } |
| 633 | 652 |
| 634 bool SourceState::OnNewBuffers( | 653 bool SourceState::OnNewBuffers( |
| 635 const StreamParser::BufferQueue& audio_buffers, | 654 const StreamParser::BufferQueue& audio_buffers, |
| 636 const StreamParser::BufferQueue& video_buffers, | 655 const StreamParser::BufferQueue& video_buffers, |
| 637 const StreamParser::TextBufferQueueMap& text_map) { | 656 const StreamParser::TextBufferQueueMap& text_map) { |
| 638 DVLOG(2) << "OnNewBuffers()"; | 657 DVLOG(2) << "OnNewBuffers()"; |
| 639 DCHECK(timestamp_offset_during_append_); | 658 DCHECK(timestamp_offset_during_append_); |
| 640 | 659 |
| 641 return frame_processor_->ProcessFrames( | 660 const TimeDelta timestamp_offset_before_processing = |
| 642 audio_buffers, video_buffers, text_map, | 661 *timestamp_offset_during_append_; |
| 643 append_window_start_during_append_, append_window_end_during_append_, | 662 |
| 644 &new_media_segment_, timestamp_offset_during_append_); | 663 // Update the timestamp offset for audio/video tracks if it hasn't already |
|
acolwell GONE FROM CHROMIUM
2014/03/18 19:57:16
nit: Please fix comment since you are only computi
DaleCurtis
2014/03/18 20:37:57
Done.
| |
| 664 // been updated by the frame processor. | |
| 665 TimeDelta new_timestamp_offset = timestamp_offset_before_processing; | |
| 666 const bool have_audio_buffers = !audio_buffers.empty(); | |
|
wolenetz
2014/03/18 20:23:33
nit: move these bools and their initializations in
DaleCurtis
2014/03/18 20:37:57
Done.
| |
| 667 const bool have_video_buffers = !video_buffers.empty(); | |
| 668 if (auto_update_timestamp_offset_) { | |
| 669 if (have_audio_buffers && have_video_buffers) { | |
| 670 new_timestamp_offset += | |
| 671 std::min(EndTimestamp(audio_buffers), EndTimestamp(video_buffers)); | |
| 672 } else if (have_audio_buffers) { | |
| 673 new_timestamp_offset += EndTimestamp(audio_buffers); | |
| 674 } else if (have_video_buffers) { | |
| 675 new_timestamp_offset += EndTimestamp(video_buffers); | |
| 676 } | |
| 677 } | |
| 678 | |
| 679 if (!frame_processor_->ProcessFrames(audio_buffers, | |
| 680 video_buffers, | |
| 681 text_map, | |
| 682 append_window_start_during_append_, | |
| 683 append_window_end_during_append_, | |
| 684 &new_media_segment_, | |
| 685 timestamp_offset_during_append_)) { | |
| 686 return false; | |
| 687 } | |
| 688 | |
| 689 // Only update the timestamp offset if the frame processor hasn't already. | |
| 690 if (timestamp_offset_before_processing == *timestamp_offset_during_append_) | |
|
wolenetz
2014/03/18 20:23:33
nit: though currently correct, add condition auto_
DaleCurtis
2014/03/18 20:37:57
Done.
| |
| 691 *timestamp_offset_during_append_ = new_timestamp_offset; | |
| 692 | |
| 693 return true; | |
| 694 } | |
| 695 | |
| 696 void SourceState::OnSourceInitDone(bool success, | |
| 697 TimeDelta duration, | |
| 698 bool auto_update_timestamp_offset) { | |
| 699 auto_update_timestamp_offset_ = auto_update_timestamp_offset; | |
| 700 base::ResetAndReturn(&init_cb_).Run(success, duration); | |
| 645 } | 701 } |
| 646 | 702 |
| 647 ChunkDemuxerStream::ChunkDemuxerStream(Type type) | 703 ChunkDemuxerStream::ChunkDemuxerStream(Type type) |
| 648 : type_(type), | 704 : type_(type), |
| 649 state_(UNINITIALIZED) { | 705 state_(UNINITIALIZED) { |
| 650 } | 706 } |
| 651 | 707 |
| 652 void ChunkDemuxerStream::StartReturningData() { | 708 void ChunkDemuxerStream::StartReturningData() { |
| 653 DVLOG(1) << "ChunkDemuxerStream::StartReturningData()"; | 709 DVLOG(1) << "ChunkDemuxerStream::StartReturningData()"; |
| 654 base::AutoLock auto_lock(lock_); | 710 base::AutoLock auto_lock(lock_); |
| (...skipping 918 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1573 } | 1629 } |
| 1574 | 1630 |
| 1575 void ChunkDemuxer::ShutdownAllStreams() { | 1631 void ChunkDemuxer::ShutdownAllStreams() { |
| 1576 for (SourceStateMap::iterator itr = source_state_map_.begin(); | 1632 for (SourceStateMap::iterator itr = source_state_map_.begin(); |
| 1577 itr != source_state_map_.end(); ++itr) { | 1633 itr != source_state_map_.end(); ++itr) { |
| 1578 itr->second->Shutdown(); | 1634 itr->second->Shutdown(); |
| 1579 } | 1635 } |
| 1580 } | 1636 } |
| 1581 | 1637 |
| 1582 } // namespace media | 1638 } // namespace media |
| OLD | NEW |