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, base::TimeDelta)> InitCB; | |
|
acolwell GONE FROM CHROMIUM
2014/03/18 00:21:54
nit: drop base::
DaleCurtis
2014/03/18 01:26:56
Done.
| |
| 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( |
| 224 scoped_ptr<StreamParser> stream_parser, | 244 scoped_ptr<StreamParser> stream_parser, |
| 225 scoped_ptr<FrameProcessorBase> frame_processor, | 245 scoped_ptr<FrameProcessorBase> frame_processor, |
| 226 const LogCB& log_cb, | 246 const LogCB& log_cb, |
| 227 const CreateDemuxerStreamCB& create_demuxer_stream_cb) | 247 const CreateDemuxerStreamCB& create_demuxer_stream_cb) |
| 228 : create_demuxer_stream_cb_(create_demuxer_stream_cb), | 248 : create_demuxer_stream_cb_(create_demuxer_stream_cb), |
| 229 timestamp_offset_during_append_(NULL), | 249 timestamp_offset_during_append_(NULL), |
| 230 new_media_segment_(false), | 250 new_media_segment_(false), |
| 231 parsing_media_segment_(false), | 251 parsing_media_segment_(false), |
| 232 stream_parser_(stream_parser.release()), | 252 stream_parser_(stream_parser.release()), |
| 233 audio_(NULL), | 253 audio_(NULL), |
| 234 video_(NULL), | 254 video_(NULL), |
| 235 frame_processor_(frame_processor.release()), | 255 frame_processor_(frame_processor.release()), |
| 236 log_cb_(log_cb) { | 256 log_cb_(log_cb), |
| 257 auto_update_timestamp_offset_(false) { | |
| 237 DCHECK(!create_demuxer_stream_cb_.is_null()); | 258 DCHECK(!create_demuxer_stream_cb_.is_null()); |
| 238 DCHECK(frame_processor_); | 259 DCHECK(frame_processor_); |
| 239 } | 260 } |
| 240 | 261 |
| 241 SourceState::~SourceState() { | 262 SourceState::~SourceState() { |
| 242 Shutdown(); | 263 Shutdown(); |
| 243 | 264 |
| 244 STLDeleteValues(&text_stream_map_); | 265 STLDeleteValues(&text_stream_map_); |
| 245 } | 266 } |
| 246 | 267 |
| 247 void SourceState::Init(const StreamParser::InitCB& init_cb, | 268 void SourceState::Init(const InitCB& init_cb, |
| 248 bool allow_audio, | 269 bool allow_audio, |
| 249 bool allow_video, | 270 bool allow_video, |
| 250 const StreamParser::NeedKeyCB& need_key_cb, | 271 const StreamParser::NeedKeyCB& need_key_cb, |
| 251 const NewTextTrackCB& new_text_track_cb) { | 272 const NewTextTrackCB& new_text_track_cb) { |
| 252 new_text_track_cb_ = new_text_track_cb; | 273 new_text_track_cb_ = new_text_track_cb; |
| 274 init_cb_ = init_cb; | |
| 253 | 275 |
| 254 stream_parser_->Init(init_cb, | 276 stream_parser_->Init(base::Bind(&SourceState::OnSourceInitDone, |
| 277 base::Unretained(this)), | |
| 255 base::Bind(&SourceState::OnNewConfigs, | 278 base::Bind(&SourceState::OnNewConfigs, |
| 256 base::Unretained(this), | 279 base::Unretained(this), |
| 257 allow_audio, | 280 allow_audio, |
| 258 allow_video), | 281 allow_video), |
| 259 base::Bind(&SourceState::OnNewBuffers, | 282 base::Bind(&SourceState::OnNewBuffers, |
| 260 base::Unretained(this)), | 283 base::Unretained(this)), |
| 261 new_text_track_cb_.is_null(), | 284 new_text_track_cb_.is_null(), |
| 262 need_key_cb, | 285 need_key_cb, |
| 263 base::Bind(&SourceState::OnNewMediaSegment, | 286 base::Bind(&SourceState::OnNewMediaSegment, |
| 264 base::Unretained(this)), | 287 base::Unretained(this)), |
| (...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 631 new_media_segment_ = false; | 654 new_media_segment_ = false; |
| 632 } | 655 } |
| 633 | 656 |
| 634 bool SourceState::OnNewBuffers( | 657 bool SourceState::OnNewBuffers( |
| 635 const StreamParser::BufferQueue& audio_buffers, | 658 const StreamParser::BufferQueue& audio_buffers, |
| 636 const StreamParser::BufferQueue& video_buffers, | 659 const StreamParser::BufferQueue& video_buffers, |
| 637 const StreamParser::TextBufferQueueMap& text_map) { | 660 const StreamParser::TextBufferQueueMap& text_map) { |
| 638 DVLOG(2) << "OnNewBuffers()"; | 661 DVLOG(2) << "OnNewBuffers()"; |
| 639 DCHECK(timestamp_offset_during_append_); | 662 DCHECK(timestamp_offset_during_append_); |
| 640 | 663 |
| 641 return frame_processor_->ProcessFrames( | 664 const TimeDelta current_timestamp_offset = *timestamp_offset_during_append_; |
| 642 audio_buffers, video_buffers, text_map, | 665 const bool success = |
| 643 append_window_start_during_append_, append_window_end_during_append_, | 666 frame_processor_->ProcessFrames(audio_buffers, |
| 644 &new_media_segment_, timestamp_offset_during_append_); | 667 video_buffers, |
| 668 text_map, | |
| 669 append_window_start_during_append_, | |
| 670 append_window_end_during_append_, | |
| 671 &new_media_segment_, | |
| 672 timestamp_offset_during_append_); | |
| 673 | |
| 674 // Update the timestamp offset for audio/video tracks if it hasn't already | |
| 675 // been updated by the frame processor. | |
| 676 const bool have_audio_buffers = !audio_buffers.empty(); | |
| 677 const bool have_video_buffers = !video_buffers.empty(); | |
| 678 if (auto_update_timestamp_offset_ && | |
| 679 current_timestamp_offset == *timestamp_offset_during_append_) { | |
| 680 if (have_audio_buffers && have_video_buffers) { | |
| 681 *timestamp_offset_during_append_ = | |
| 682 std::min(EndTimestamp(audio_buffers), EndTimestamp(video_buffers)); | |
| 683 } else if (have_audio_buffers) { | |
| 684 *timestamp_offset_during_append_ = EndTimestamp(audio_buffers); | |
| 685 } else if (have_video_buffers) { | |
| 686 *timestamp_offset_during_append_ = EndTimestamp(video_buffers); | |
| 687 } | |
| 688 } | |
| 689 | |
| 690 return success; | |
| 691 } | |
| 692 | |
| 693 void SourceState::OnSourceInitDone(bool success, | |
| 694 TimeDelta duration, | |
| 695 bool auto_update_timestamp_offset) { | |
| 696 auto_update_timestamp_offset_ = auto_update_timestamp_offset; | |
| 697 init_cb_.Run(success, duration); | |
|
acolwell GONE FROM CHROMIUM
2014/03/18 00:21:54
nit: Use base::ResetAndReturn(&init_cb_) here.
DaleCurtis
2014/03/18 01:26:56
Done.
| |
| 645 } | 698 } |
| 646 | 699 |
| 647 ChunkDemuxerStream::ChunkDemuxerStream(Type type) | 700 ChunkDemuxerStream::ChunkDemuxerStream(Type type) |
| 648 : type_(type), | 701 : type_(type), |
| 649 state_(UNINITIALIZED) { | 702 state_(UNINITIALIZED) { |
| 650 } | 703 } |
| 651 | 704 |
| 652 void ChunkDemuxerStream::StartReturningData() { | 705 void ChunkDemuxerStream::StartReturningData() { |
| 653 DVLOG(1) << "ChunkDemuxerStream::StartReturningData()"; | 706 DVLOG(1) << "ChunkDemuxerStream::StartReturningData()"; |
| 654 base::AutoLock auto_lock(lock_); | 707 base::AutoLock auto_lock(lock_); |
| (...skipping 755 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1410 for (SourceStateMap::const_iterator itr = source_state_map_.begin(); | 1463 for (SourceStateMap::const_iterator itr = source_state_map_.begin(); |
| 1411 itr != source_state_map_.end(); ++itr) { | 1464 itr != source_state_map_.end(); ++itr) { |
| 1412 if (itr->second->IsSeekWaitingForData()) | 1465 if (itr->second->IsSeekWaitingForData()) |
| 1413 return true; | 1466 return true; |
| 1414 } | 1467 } |
| 1415 | 1468 |
| 1416 return false; | 1469 return false; |
| 1417 } | 1470 } |
| 1418 | 1471 |
| 1419 void ChunkDemuxer::OnSourceInitDone(bool success, TimeDelta duration) { | 1472 void ChunkDemuxer::OnSourceInitDone(bool success, TimeDelta duration) { |
| 1420 DVLOG(1) << "OnSourceInitDone(" << success << ", " | 1473 DVLOG(1) << "OnSourceInitDone(" << success |
| 1421 << duration.InSecondsF() << ")"; | 1474 << ", " << duration.InSecondsF() << ")"; |
| 1422 lock_.AssertAcquired(); | 1475 lock_.AssertAcquired(); |
| 1423 DCHECK_EQ(state_, INITIALIZING); | 1476 DCHECK_EQ(state_, INITIALIZING); |
| 1424 if (!success || (!audio_ && !video_)) { | 1477 if (!success || (!audio_ && !video_)) { |
| 1425 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); | 1478 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); |
| 1426 return; | 1479 return; |
| 1427 } | 1480 } |
| 1428 | 1481 |
| 1429 if (duration != TimeDelta() && duration_ == kNoTimestamp()) | 1482 if (duration != TimeDelta() && duration_ == kNoTimestamp()) |
| 1430 UpdateDuration(duration); | 1483 UpdateDuration(duration); |
| 1431 | 1484 |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1573 } | 1626 } |
| 1574 | 1627 |
| 1575 void ChunkDemuxer::ShutdownAllStreams() { | 1628 void ChunkDemuxer::ShutdownAllStreams() { |
| 1576 for (SourceStateMap::iterator itr = source_state_map_.begin(); | 1629 for (SourceStateMap::iterator itr = source_state_map_.begin(); |
| 1577 itr != source_state_map_.end(); ++itr) { | 1630 itr != source_state_map_.end(); ++itr) { |
| 1578 itr->second->Shutdown(); | 1631 itr->second->Shutdown(); |
| 1579 } | 1632 } |
| 1580 } | 1633 } |
| 1581 | 1634 |
| 1582 } // namespace media | 1635 } // namespace media |
| OLD | NEW |