Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(495)

Side by Side Diff: media/filters/chunk_demuxer.cc

Issue 361023003: WIP fixing/extending acolwell's init-segment-received patch Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebased to ToT. Lots of further work needed (BIG TODOs, nits-to-self, etc) Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « media/filters/chunk_demuxer.h ('k') | media/filters/chunk_demuxer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/frame_processor.h" 20 #include "media/filters/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 using TextTrackConfigMap = media::StreamParser::TextTrackConfigMap;
24 25
25 namespace media { 26 namespace media {
26 27
27 static TimeDelta EndTimestamp(const StreamParser::BufferQueue& queue) { 28 static TimeDelta EndTimestamp(const StreamParser::BufferQueue& queue) {
28 return queue.back()->timestamp() + queue.back()->duration(); 29 return queue.back()->timestamp() + queue.back()->duration();
29 } 30 }
30 31
31 // List of time ranges for each SourceBuffer. 32 // List of time ranges for each SourceBuffer.
32 typedef std::list<Ranges<TimeDelta> > RangesList; 33 typedef std::list<Ranges<TimeDelta> > RangesList;
33 static Ranges<TimeDelta> ComputeIntersection(const RangesList& activeRanges, 34 static Ranges<TimeDelta> ComputeIntersection(const RangesList& activeRanges,
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
76 // Step 5.3: Let new intersection ranges equal the intersection between 77 // Step 5.3: Let new intersection ranges equal the intersection between
77 // the intersection ranges and the source ranges. 78 // the intersection ranges and the source ranges.
78 // Step 5.4: Replace the ranges in intersection ranges with the new 79 // Step 5.4: Replace the ranges in intersection ranges with the new
79 // intersection ranges. 80 // intersection ranges.
80 intersection_ranges = intersection_ranges.IntersectionWith(source_ranges); 81 intersection_ranges = intersection_ranges.IntersectionWith(source_ranges);
81 } 82 }
82 83
83 return intersection_ranges; 84 return intersection_ranges;
84 } 85 }
85 86
87 InitSegment::InitSegment(const std::vector<AudioTrackInfo>& audio,
88 const std::vector<VideoTrackInfo>& video,
89 const std::vector<TextTrackInfo>& text) :
90 audio_tracks(audio),
91 video_tracks(video),
92 text_tracks(text) {
93 }
94
95 InitSegment::~InitSegment() {
96 }
97
98 InitSegment InitSegment::Create(
99 const AudioDecoderConfig& audio_config,
100 const VideoDecoderConfig& video_config,
101 const StreamParser::TextTrackConfigMap& text_configs) {
102 std::vector<AudioTrackInfo> audio_tracks;
103 std::vector<VideoTrackInfo> video_tracks;
104 std::vector<TextTrackInfo> text_tracks;
105
106 // BIG TODO: Reject/decode error on Invalid Configs??
107 // BIG TODO START HERE: Get Blink integration working...
108
109 if (audio_config.IsValidConfig())
110 audio_tracks.push_back(AudioTrackInfo(FrameProcessor::kAudioTrackId,
111 audio_config));
112
113 if (video_config.IsValidConfig())
114 video_tracks.push_back(VideoTrackInfo(FrameProcessor::kVideoTrackId,
115 video_config));
116
117 for (TextTrackConfigMap::const_iterator itr = text_configs.begin();
118 itr != text_configs.end(); ++itr) {
119 text_tracks.push_back(TextTrackInfo(itr->first, itr->second));
120 }
121
122 return InitSegment(audio_tracks, video_tracks, text_tracks);
123 }
124
125 bool InitSegment::HasTracks() const {
126 return !audio_tracks.empty() || !video_tracks.empty() || !text_tracks.empty();
127 }
128
86 // Contains state belonging to a source id. 129 // Contains state belonging to a source id.
87 class SourceState { 130 class SourceState {
88 public: 131 public:
132 typedef ChunkDemuxer::NewInitSegmentCB NewInitSegmentCB;
133
89 // Callback signature used to create ChunkDemuxerStreams. 134 // Callback signature used to create ChunkDemuxerStreams.
90 typedef base::Callback<ChunkDemuxerStream*( 135 typedef base::Callback<ChunkDemuxerStream*(
91 DemuxerStream::Type)> CreateDemuxerStreamCB; 136 DemuxerStream::Type)> CreateDemuxerStreamCB;
92 137
93 typedef base::Callback<void( 138 typedef base::Callback<void(
94 ChunkDemuxerStream*, const TextTrackConfig&)> NewTextTrackCB; 139 ChunkDemuxerStream*, const TextTrackConfig&)> NewTextTrackCB;
95 140
96 SourceState( 141 SourceState(
97 scoped_ptr<StreamParser> stream_parser, 142 scoped_ptr<StreamParser> stream_parser,
98 scoped_ptr<FrameProcessor> frame_processor, const LogCB& log_cb, 143 scoped_ptr<FrameProcessor> frame_processor,
144 const LogCB& log_cb,
145 const NewInitSegmentCB& new_init_segment_cb,
99 const CreateDemuxerStreamCB& create_demuxer_stream_cb); 146 const CreateDemuxerStreamCB& create_demuxer_stream_cb);
100 147
101 ~SourceState(); 148 ~SourceState();
102 149
103 void Init(const StreamParser::InitCB& init_cb, 150 void Init(const StreamParser::InitCB& init_cb,
104 bool allow_audio, 151 bool allow_audio,
105 bool allow_video, 152 bool allow_video,
106 const StreamParser::NeedKeyCB& need_key_cb, 153 const StreamParser::NeedKeyCB& need_key_cb,
107 const NewTextTrackCB& new_text_track_cb); 154 const NewTextTrackCB& new_text_track_cb);
108 155
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
155 void OnSetDuration(TimeDelta duration); 202 void OnSetDuration(TimeDelta duration);
156 void MarkEndOfStream(); 203 void MarkEndOfStream();
157 void UnmarkEndOfStream(); 204 void UnmarkEndOfStream();
158 void Shutdown(); 205 void Shutdown();
159 // Sets the memory limit on each stream. |memory_limit| is the 206 // Sets the memory limit on each stream. |memory_limit| is the
160 // maximum number of bytes each stream is allowed to hold in its buffer. 207 // maximum number of bytes each stream is allowed to hold in its buffer.
161 void SetMemoryLimitsForTesting(int memory_limit); 208 void SetMemoryLimitsForTesting(int memory_limit);
162 bool IsSeekWaitingForData() const; 209 bool IsSeekWaitingForData() const;
163 210
164 private: 211 private:
165 // Called by the |stream_parser_| when a new initialization segment is 212 // Called by the |stream_parse_| when a new initialization segment is
166 // encountered. 213 // encountered. This method implements the "Initialization segment received"
214 // algorithm outlined in the MSE spec.
215 //
167 // Returns true on a successful call. Returns false if an error occurred while 216 // Returns true on a successful call. Returns false if an error occurred while
168 // processing decoder configurations. 217 // processing decoder configurations.
169 bool OnNewConfigs(bool allow_audio, bool allow_video, 218 bool OnInitSegment(bool allow_audio, bool allow_video,
170 const AudioDecoderConfig& audio_config, 219 const AudioDecoderConfig& audio_config,
171 const VideoDecoderConfig& video_config, 220 const VideoDecoderConfig& video_config,
172 const StreamParser::TextTrackConfigMap& text_configs); 221 const StreamParser::TextTrackConfigMap& text_configs);
222
223 // Implements step 3.1 - 3.3 of the "Initialization segment received"
224 // algorithm.
225 bool ValidateInitSegmentAndUpdateStreams(const InitSegment& init_segment);
226
227 // Implements step 5.1 of the "Initialization segment received" algorithm.
228 bool HasUnsupportedCodecs(bool allow_audio, bool allow_video,
229 const InitSegment& init_segment) const;
230
231 // Implements step 5.3 of the "Initialization segment received" algorithm.
232 bool HandleNewAudioTracks(const std::vector<AudioTrackInfo>& audio_tracks);
233
234 // Implements step 5.4 of the "Initialization segment received" algorithm.
235 bool HandleNewVideoTracks(const std::vector<VideoTrackInfo>& video_tracks);
236
237 // Implements step 5.4 of the "Initialization segment received" algorithm.
238 bool HandleNewTextTracks(const std::vector<TextTrackInfo>& text_tracks);
173 239
174 // Called by the |stream_parser_| at the beginning of a new media segment. 240 // Called by the |stream_parser_| at the beginning of a new media segment.
175 void OnNewMediaSegment(); 241 void OnNewMediaSegment();
176 242
177 // Called by the |stream_parser_| at the end of a media segment. 243 // Called by the |stream_parser_| at the end of a media segment.
178 void OnEndOfMediaSegment(); 244 void OnEndOfMediaSegment();
179 245
180 // Called by the |stream_parser_| when new buffers have been parsed. 246 // Called by the |stream_parser_| when new buffers have been parsed.
181 // It processes the new buffers using |frame_processor_|, which includes 247 // It processes the new buffers using |frame_processor_|, which includes
182 // appending the processed frames to associated demuxer streams for each 248 // appending the processed frames to associated demuxer streams for each
183 // frame's track. 249 // frame's track.
184 // Returns true on a successful call. Returns false if an error occurred while 250 // Returns true on a successful call. Returns false if an error occurred while
185 // processing the buffers. 251 // processing the buffers.
186 bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers, 252 bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers,
187 const StreamParser::BufferQueue& video_buffers, 253 const StreamParser::BufferQueue& video_buffers,
188 const StreamParser::TextBufferQueueMap& text_map); 254 const StreamParser::TextBufferQueueMap& text_map);
189 255
190 void OnSourceInitDone(bool success, 256 void OnSourceInitDone(bool success,
191 const StreamParser::InitParameters& params); 257 const StreamParser::InitParameters& params);
192 258
259 NewInitSegmentCB new_init_segment_cb_;
193 CreateDemuxerStreamCB create_demuxer_stream_cb_; 260 CreateDemuxerStreamCB create_demuxer_stream_cb_;
194 NewTextTrackCB new_text_track_cb_; 261 NewTextTrackCB new_text_track_cb_;
195 262
196 // During Append(), if OnNewBuffers() coded frame processing updates the 263 // During Append(), if OnNewBuffers() coded frame processing updates the
197 // timestamp offset then |*timestamp_offset_during_append_| is also updated 264 // timestamp offset then |*timestamp_offset_during_append_| is also updated
198 // so Append()'s caller can know the new offset. This pointer is only non-NULL 265 // so Append()'s caller can know the new offset. This pointer is only non-NULL
199 // during the lifetime of an Append() call. 266 // during the lifetime of an Append() call.
200 TimeDelta* timestamp_offset_during_append_; 267 TimeDelta* timestamp_offset_during_append_;
201 268
202 // During Append(), coded frame processing triggered by OnNewBuffers() 269 // During Append(), coded frame processing triggered by OnNewBuffers()
203 // requires these two attributes. These are only valid during the lifetime of 270 // requires these two attributes. These are only valid during the lifetime of
204 // an Append() call. 271 // an Append() call.
205 TimeDelta append_window_start_during_append_; 272 TimeDelta append_window_start_during_append_;
206 TimeDelta append_window_end_during_append_; 273 TimeDelta append_window_end_during_append_;
207 274
208 // Set to true if the next buffers appended within the append window 275 // Set to true if the next buffers appended within the append window
209 // represent the start of a new media segment. This flag being set 276 // represent the start of a new media segment. This flag being set
210 // triggers a call to |new_segment_cb_| when the new buffers are 277 // triggers a call to |new_segment_cb_| when the new buffers are
211 // appended. The flag is set on actual media segment boundaries and 278 // appended. The flag is set on actual media segment boundaries and
212 // when the "append window" filtering causes discontinuities in the 279 // when the "append window" filtering causes discontinuities in the
213 // appended data. 280 // appended data.
214 // TODO(wolenetz/acolwell): Investigate if we need this, or if coded frame 281 // TODO(wolenetz/acolwell): Investigate if we need this, or if coded frame
215 // processing's discontinuity logic is enough. See http://crbug.com/351489. 282 // processing's discontinuity logic is enough. See http://crbug.com/351489.
216 bool new_media_segment_; 283 bool new_media_segment_;
217 284
218 // Keeps track of whether a media segment is being parsed. 285 // Keeps track of whether a media segment is being parsed.
219 bool parsing_media_segment_; 286 bool parsing_media_segment_;
220 287
288 // Keeps track of the "first initialization segment flag" state mentioned in
289 // the MSE spec.
290 bool received_first_init_segment_;
291
221 // The object used to parse appended data. 292 // The object used to parse appended data.
222 scoped_ptr<StreamParser> stream_parser_; 293 scoped_ptr<StreamParser> stream_parser_;
223 294
224 ChunkDemuxerStream* audio_; // Not owned by |this|. 295 ChunkDemuxerStream* audio_; // Not owned by |this|.
225 ChunkDemuxerStream* video_; // Not owned by |this|. 296 ChunkDemuxerStream* video_; // Not owned by |this|.
226 297
227 typedef std::map<StreamParser::TrackId, ChunkDemuxerStream*> TextStreamMap; 298 typedef std::map<StreamParser::TrackId, ChunkDemuxerStream*> TextStreamMap;
228 TextStreamMap text_stream_map_; // |this| owns the map's stream pointers. 299 TextStreamMap text_stream_map_; // |this| owns the map's stream pointers.
229 300
230 scoped_ptr<FrameProcessor> frame_processor_; 301 scoped_ptr<FrameProcessor> frame_processor_;
231 LogCB log_cb_; 302 LogCB log_cb_;
232 StreamParser::InitCB init_cb_; 303 StreamParser::InitCB init_cb_;
233 304
234 // Indicates that timestampOffset should be updated automatically during 305 // Indicates that timestampOffset should be updated automatically during
235 // OnNewBuffers() based on the earliest end timestamp of the buffers provided. 306 // OnNewBuffers() based on the earliest end timestamp of the buffers provided.
236 // TODO(wolenetz): Refactor this function while integrating April 29, 2014 307 // TODO(wolenetz): Refactor this function while integrating April 29, 2014
237 // changes to MSE spec. See http://crbug.com/371499. 308 // changes to MSE spec. See http://crbug.com/371499.
238 bool auto_update_timestamp_offset_; 309 bool auto_update_timestamp_offset_;
239 310
240 DISALLOW_COPY_AND_ASSIGN(SourceState); 311 DISALLOW_COPY_AND_ASSIGN(SourceState);
241 }; 312 };
242 313
243 SourceState::SourceState(scoped_ptr<StreamParser> stream_parser, 314 SourceState::SourceState(scoped_ptr<StreamParser> stream_parser,
244 scoped_ptr<FrameProcessor> frame_processor, 315 scoped_ptr<FrameProcessor> frame_processor,
245 const LogCB& log_cb, 316 const LogCB& log_cb,
317 const NewInitSegmentCB& new_init_segment_cb,
246 const CreateDemuxerStreamCB& create_demuxer_stream_cb) 318 const CreateDemuxerStreamCB& create_demuxer_stream_cb)
247 : create_demuxer_stream_cb_(create_demuxer_stream_cb), 319 : new_init_segment_cb_(new_init_segment_cb),
320 create_demuxer_stream_cb_(create_demuxer_stream_cb),
248 timestamp_offset_during_append_(NULL), 321 timestamp_offset_during_append_(NULL),
249 new_media_segment_(false), 322 new_media_segment_(false),
250 parsing_media_segment_(false), 323 parsing_media_segment_(false),
324 received_first_init_segment_(false),
251 stream_parser_(stream_parser.release()), 325 stream_parser_(stream_parser.release()),
252 audio_(NULL), 326 audio_(NULL),
253 video_(NULL), 327 video_(NULL),
254 frame_processor_(frame_processor.release()), 328 frame_processor_(frame_processor.release()),
255 log_cb_(log_cb), 329 log_cb_(log_cb),
256 auto_update_timestamp_offset_(false) { 330 auto_update_timestamp_offset_(false) {
257 DCHECK(!create_demuxer_stream_cb_.is_null()); 331 DCHECK(!create_demuxer_stream_cb_.is_null());
258 DCHECK(frame_processor_); 332 DCHECK(frame_processor_);
259 } 333 }
260 334
261 SourceState::~SourceState() { 335 SourceState::~SourceState() {
262 Shutdown(); 336 Shutdown();
263 337
264 STLDeleteValues(&text_stream_map_); 338 STLDeleteValues(&text_stream_map_);
265 } 339 }
266 340
267 void SourceState::Init(const StreamParser::InitCB& init_cb, 341 void SourceState::Init(const StreamParser::InitCB& init_cb,
268 bool allow_audio, 342 bool allow_audio,
269 bool allow_video, 343 bool allow_video,
270 const StreamParser::NeedKeyCB& need_key_cb, 344 const StreamParser::NeedKeyCB& need_key_cb,
271 const NewTextTrackCB& new_text_track_cb) { 345 const NewTextTrackCB& new_text_track_cb) {
272 new_text_track_cb_ = new_text_track_cb; 346 new_text_track_cb_ = new_text_track_cb;
273 init_cb_ = init_cb; 347 init_cb_ = init_cb;
274 348
275 stream_parser_->Init( 349 stream_parser_->Init(
276 base::Bind(&SourceState::OnSourceInitDone, base::Unretained(this)), 350 base::Bind(&SourceState::OnSourceInitDone, base::Unretained(this)),
277 base::Bind(&SourceState::OnNewConfigs, 351 base::Bind(&SourceState::OnInitSegment,
278 base::Unretained(this), 352 base::Unretained(this),
279 allow_audio, 353 allow_audio,
280 allow_video), 354 allow_video),
281 base::Bind(&SourceState::OnNewBuffers, base::Unretained(this)), 355 base::Bind(&SourceState::OnNewBuffers, base::Unretained(this)),
282 new_text_track_cb_.is_null(), 356 new_text_track_cb_.is_null(),
283 need_key_cb, 357 need_key_cb,
284 base::Bind(&SourceState::OnNewMediaSegment, base::Unretained(this)), 358 base::Bind(&SourceState::OnNewMediaSegment, base::Unretained(this)),
285 base::Bind(&SourceState::OnEndOfMediaSegment, base::Unretained(this)), 359 base::Bind(&SourceState::OnEndOfMediaSegment, base::Unretained(this)),
286 log_cb_); 360 log_cb_);
287 } 361 }
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after
508 // NOTE: We are intentionally not checking the text tracks 582 // NOTE: We are intentionally not checking the text tracks
509 // because text tracks are discontinuous and may not have data 583 // because text tracks are discontinuous and may not have data
510 // for the seek position. This is ok and playback should not be 584 // for the seek position. This is ok and playback should not be
511 // stalled because we don't have cues. If cues, with timestamps after 585 // stalled because we don't have cues. If cues, with timestamps after
512 // the seek time, eventually arrive they will be delivered properly 586 // the seek time, eventually arrive they will be delivered properly
513 // in response to ChunkDemuxerStream::Read() calls. 587 // in response to ChunkDemuxerStream::Read() calls.
514 588
515 return false; 589 return false;
516 } 590 }
517 591
518 bool SourceState::OnNewConfigs( 592 bool SourceState::OnInitSegment(
519 bool allow_audio, bool allow_video, 593 bool allow_audio, bool allow_video,
520 const AudioDecoderConfig& audio_config, 594 const AudioDecoderConfig& audio_config,
521 const VideoDecoderConfig& video_config, 595 const VideoDecoderConfig& video_config,
522 const StreamParser::TextTrackConfigMap& text_configs) { 596 const StreamParser::TextTrackConfigMap& text_configs) {
523 DVLOG(1) << "OnNewConfigs(" << allow_audio << ", " << allow_video 597 DVLOG(2) << "OnInitSegment() "
524 << ", " << audio_config.IsValidConfig() 598 << ": allow_audio=" << allow_audio
525 << ", " << video_config.IsValidConfig() << ")"; 599 << ", allow_video=" << allow_video
526 600 << ", audio_config is "
527 if (!audio_config.IsValidConfig() && !video_config.IsValidConfig()) { 601 << (audio_config.IsValidConfig() ? "valid" : "invalid")
528 DVLOG(1) << "OnNewConfigs() : Audio & video config are not valid!"; 602 << ", video_config is "
529 return false; 603 << (video_config.IsValidConfig() ? "valid" : "invalid")
530 } 604 << ", text_configs.size()=" << text_configs.size();
531 605
532 // Signal an error if we get configuration info for stream types that weren't 606 // TODO(wolenetz/acolwell): Update StreamParser interface to emit InitSegments
533 // specified in AddId() or more configs after a stream is initialized. 607 // instead of individual configs.
534 if (allow_audio != audio_config.IsValidConfig()) { 608 InitSegment init_segment =
609 InitSegment::Create(audio_config, video_config, text_configs);
610
611 // Section 3.5.7 Initialization Segment Received
612 // 1. Update the duration attribute if it currently equals NaN:
613 // If the initialization segment contains a duration:
614 // 1. Run the duration change algorithm with new duration set to the
615 // duration in the initialization segment.
616 // Otherwise:
617 // 1. Run the duration change algorithm with new duration set to positive
618 // Infinity.
619 // TODO(wolenetz/acolwell): Refactor code so step 1 can actually be done here.
620
621 // 2. If the initialization segment has no audio, video, or text tracks, then
622 // run the end of stream algorithm with the error parameter set to "decode"
623 // and abort these steps.
624 if (!init_segment.HasTracks()) {
625 MEDIA_LOG(log_cb_) << "No audio, video or text tracks "
626 << "in initialization segment";
627 return false;
628 }
629
630 // 3. If the first initialization segment flag is true, then run the following
631 // steps:
632 if (received_first_init_segment_) {
633 // 3.1 Verify the following properties. If any of the checks fail then run
634 // the end of stream algorithm with the error parameter set to "decode"
635 // and abort these steps.
636 // * The number of audio, video, and text tracks match what was in the
637 // first initialization segment.
638 // * The codecs for each track match what was specified in the first
639 // initialization segment.
640 // * If more than one track for a single type are present (ie 2 audio
641 // tracks), then the Track IDs match the ones in the first
642 // initialization segment.
643 // 3.2 Add the appropriate track descriptions from this initialization
644 // segment to each of the track buffers.
645 // 3.3 Set the need random access point flag on all track buffers to true.
646 if (!ValidateInitSegmentAndUpdateStreams(init_segment))
647 return false;
648 }
649
650 // 4. Let active track flag equal false.
651 // Note: This step is handled in Blink.
652 // BIG TODO(wolenetz): confirm Blink does this...
653
654 // 5. If the first initialization segment flag is false, then run the
655 // following steps:
656 // BIG TODO(wolenetz): confirm the spec steps match the comments here and the
657 // SourceState declaration comments.
658 if (!received_first_init_segment_) {
659 // 5.1 If the initialization segment contains tracks with codecs the user
660 // agent does not support, then run the end of stream algorithm with the
661 // error parameter set to "decode" and abort these steps.
662 if (HasUnsupportedCodecs(allow_audio, allow_video, init_segment))
663 return false;
664
665 // 5.2 For each audio track in the initialization segment, run the following
666 // steps:
667 if (!init_segment.audio_tracks.empty() &&
668 !HandleNewAudioTracks(init_segment.audio_tracks)) {
669 return false;
670 }
671
672 // 5.3 For each video track in the initialization segment, run the
673 // following steps:
674 if (!init_segment.video_tracks.empty() &&
675 !HandleNewVideoTracks(init_segment.video_tracks)) {
676 return false;
677 }
678
679 // 5.4 For each text track in the initialization segment, run the
680 // following steps:
681 if (!init_segment.text_tracks.empty() &&
682 !HandleNewTextTracks(init_segment.text_tracks)) {
683 return false;
684 }
685
686 // 5.5 If active track flag equals true, then run the following steps:
687 // NOTE: Handled when |init_segment_state| is processed by Blink.
688 // BIG TODO(wolenetz): confirm Blink does this...
689
690 // 5.6 Set first initialization segment flag to true.
691 received_first_init_segment_ = true;
692 }
693
694 // Steps 6 & 7 are handled when |init_segment_state| is processed by Blink.
695 // BIG TODO(wolenetz): confirm Blink does this...
696
697 return true;
698 }
699
700 bool SourceState::ValidateInitSegmentAndUpdateStreams(
701 const InitSegment& init_segment) {
702 if (!init_segment.audio_tracks.empty()) {
703 const AudioDecoderConfig& audio_config =
704 init_segment.audio_tracks[0].config();
705 if (!audio_ || !audio_->UpdateAudioConfig(audio_config, log_cb_))
706 return false;
707 frame_processor_->OnPossibleAudioConfigUpdate(audio_config);
708 }
709
710 if (!init_segment.video_tracks.empty() &&
711 (!video_ ||
712 !video_->UpdateVideoConfig(init_segment.video_tracks[0].config(),
713 log_cb_))) {
714 return false;
715 }
716
717 const size_t text_count = init_segment.text_tracks.size();
718 if (text_stream_map_.size() != text_count) {
719 MEDIA_LOG(log_cb_) << "The number of text track configs changed.";
720 return false;
721 }
722
723 if (text_count == 1) {
724 ChunkDemuxerStream* text_stream = text_stream_map_.begin()->second;
725 const StreamParser::TrackId old_id = text_stream_map_.begin()->first;
726 const TextTrackConfig& old_text_config = text_stream->text_track_config();
727 const StreamParser::TrackId new_id = init_segment.text_tracks[0].track_id();
728 const TextTrackConfig& new_text_config =
729 init_segment.text_tracks[0].config();
730
731 if (!new_text_config.Matches(old_text_config)) {
732 MEDIA_LOG(log_cb_) << "New text track config does not match old one.";
733 return false;
734 }
735
736 if (new_id != old_id) {
737 if (frame_processor_->UpdateTrack(old_id, new_id)) {
738 text_stream_map_.clear();
739 text_stream_map_[new_id] = text_stream;
740 } else {
741 MEDIA_LOG(log_cb_) << "Error remapping single text track number";
742 return false;
743 }
744 }
745 } else {
746 for (size_t i = 0; i < text_count; ++i) {
747 const TextTrackInfo& track_info = init_segment.text_tracks[i];
748 TextStreamMap::iterator stream_itr =
749 text_stream_map_.find(track_info.track_id());
750 if (stream_itr == text_stream_map_.end()) {
751 MEDIA_LOG(log_cb_) << "Unexpected text track configuration for track "
752 << "ID " << track_info.track_id();
753 return false;
754 }
755
756 ChunkDemuxerStream* stream = stream_itr->second;
757 if (!track_info.config().Matches(stream->text_track_config())) {
758 MEDIA_LOG(log_cb_) << "New text track config for track ID "
759 << track_info.track_id()
760 << " does not match old one.";
761 return false;
762 }
763 }
764 }
765
766 frame_processor_->SetAllTrackBuffersNeedRandomAccessPoint();
767
768 return true;
769 }
770
771 bool SourceState::HasUnsupportedCodecs(bool allow_audio, bool allow_video,
772 const InitSegment& init_segment) const {
773 bool has_audio = !init_segment.audio_tracks.empty();
774 bool has_video = !init_segment.video_tracks.empty();
775
776 if (allow_audio != has_audio) {
535 MEDIA_LOG(log_cb_) 777 MEDIA_LOG(log_cb_)
536 << "Initialization segment" 778 << "Initialization segment"
537 << (audio_config.IsValidConfig() ? " has" : " does not have") 779 << (has_audio ? " has" : " does not have")
538 << " an audio track, but the mimetype" 780 << " an audio track, but the mimetype"
539 << (allow_audio ? " specifies" : " does not specify") 781 << (allow_audio ? " specifies" : " does not specify")
540 << " an audio codec."; 782 << " an audio codec.";
541 return false; 783 return true;
542 } 784 }
543 785
544 if (allow_video != video_config.IsValidConfig()) { 786 if (allow_video != has_video) {
545 MEDIA_LOG(log_cb_) 787 MEDIA_LOG(log_cb_)
546 << "Initialization segment" 788 << "Initialization segment"
547 << (video_config.IsValidConfig() ? " has" : " does not have") 789 << (has_video ? " has" : " does not have")
548 << " a video track, but the mimetype" 790 << " a video track, but the mimetype"
549 << (allow_video ? " specifies" : " does not specify") 791 << (allow_video ? " specifies" : " does not specify")
550 << " a video codec."; 792 << " a video codec.";
551 return false; 793 return true;
552 } 794 }
553 795
554 bool success = true; 796 return false;
555 if (audio_config.IsValidConfig()) { 797 }
556 if (!audio_) { 798
557 audio_ = create_demuxer_stream_cb_.Run(DemuxerStream::AUDIO); 799 bool SourceState::HandleNewAudioTracks(
558 800 const std::vector<AudioTrackInfo>& audio_tracks) {
559 if (!audio_) { 801 DCHECK(!received_first_init_segment_);
560 DVLOG(1) << "Failed to create an audio stream."; 802 DCHECK(!audio_tracks.empty());
561 return false; 803 DCHECK(!audio_);
562 } 804 audio_ = create_demuxer_stream_cb_.Run(DemuxerStream::AUDIO);
563 805 if (!audio_) {
564 if (!frame_processor_->AddTrack(FrameProcessor::kAudioTrackId, audio_)) { 806 DVLOG(1) << "Failed to create an audio stream.";
565 DVLOG(1) << "Failed to add audio track to frame processor."; 807 return false;
566 return false; 808 }
567 } 809
568 } 810 if (!frame_processor_->AddTrack(audio_tracks[0].track_id(), audio_)) {
569 811 MEDIA_LOG(log_cb_) << "Failed to add audio track ID "
570 frame_processor_->OnPossibleAudioConfigUpdate(audio_config); 812 << audio_tracks[0].track_id()
571 success &= audio_->UpdateAudioConfig(audio_config, log_cb_); 813 << " to frame processor.";
572 } 814 return false;
573 815 }
574 if (video_config.IsValidConfig()) { 816
575 if (!video_) { 817 const AudioDecoderConfig& audio_config = audio_tracks[0].config();
576 video_ = create_demuxer_stream_cb_.Run(DemuxerStream::VIDEO); 818 frame_processor_->OnPossibleAudioConfigUpdate(audio_config);
577 819 if (!audio_->UpdateAudioConfig(audio_config, log_cb_)) {
578 if (!video_) { 820 MEDIA_LOG(log_cb_) << "Failed to set config for new audio track ID "
579 DVLOG(1) << "Failed to create a video stream."; 821 << audio_tracks[0].track_id();
580 return false; 822 return false;
581 } 823 }
582 824
583 if (!frame_processor_->AddTrack(FrameProcessor::kVideoTrackId, video_)) { 825 return true;
584 DVLOG(1) << "Failed to add video track to frame processor."; 826 }
585 return false; 827
586 } 828 bool SourceState::HandleNewVideoTracks(
587 } 829 const std::vector<VideoTrackInfo>& video_tracks) {
588 830 DCHECK(!received_first_init_segment_);
589 success &= video_->UpdateVideoConfig(video_config, log_cb_); 831 DCHECK(!video_tracks.empty());
590 } 832 DCHECK(!video_);
591 833 video_ = create_demuxer_stream_cb_.Run(DemuxerStream::VIDEO);
592 typedef StreamParser::TextTrackConfigMap::const_iterator TextConfigItr; 834 if (!video_) {
593 if (text_stream_map_.empty()) { 835 DVLOG(1) << "Failed to create a video stream.";
594 for (TextConfigItr itr = text_configs.begin(); 836 return false;
595 itr != text_configs.end(); ++itr) { 837 }
596 ChunkDemuxerStream* const text_stream = 838
597 create_demuxer_stream_cb_.Run(DemuxerStream::TEXT); 839 if (!frame_processor_->AddTrack(video_tracks[0].track_id(), video_)) {
598 if (!frame_processor_->AddTrack(itr->first, text_stream)) { 840 MEDIA_LOG(log_cb_) << "Failed to add video track ID "
599 success &= false; 841 << video_tracks[0].track_id()
600 MEDIA_LOG(log_cb_) << "Failed to add text track ID " << itr->first 842 << " to frame processor.";
601 << " to frame processor."; 843 return false;
602 break; 844 }
603 } 845
604 text_stream->UpdateTextConfig(itr->second, log_cb_); 846 if (!video_->UpdateVideoConfig(video_tracks[0].config(), log_cb_)) {
605 text_stream_map_[itr->first] = text_stream; 847 MEDIA_LOG(log_cb_) << "Failed to set config for new video track ID "
606 new_text_track_cb_.Run(text_stream, itr->second); 848 << video_tracks[0].track_id();
607 } 849 return false;
608 } else { 850 }
609 const size_t text_count = text_stream_map_.size(); 851
610 if (text_configs.size() != text_count) { 852 return true;
611 success &= false; 853 }
612 MEDIA_LOG(log_cb_) << "The number of text track configs changed."; 854
613 } else if (text_count == 1) { 855 bool SourceState::HandleNewTextTracks(
614 TextConfigItr config_itr = text_configs.begin(); 856 const std::vector<TextTrackInfo>& text_tracks) {
615 const TextTrackConfig& new_config = config_itr->second; 857 DCHECK(!received_first_init_segment_);
616 TextStreamMap::iterator stream_itr = text_stream_map_.begin(); 858 DCHECK(!text_tracks.empty());
617 ChunkDemuxerStream* text_stream = stream_itr->second; 859 DCHECK(text_stream_map_.empty());
618 TextTrackConfig old_config = text_stream->text_track_config(); 860 for (size_t i = 0; i < text_tracks.size(); ++i) {
619 if (!new_config.Matches(old_config)) { 861 const TextTrackInfo& track_info = text_tracks[i];
620 success &= false; 862 ChunkDemuxerStream* const text_stream =
621 MEDIA_LOG(log_cb_) << "New text track config does not match old one."; 863 create_demuxer_stream_cb_.Run(DemuxerStream::TEXT);
622 } else { 864 if (!text_stream) {
623 StreamParser::TrackId old_id = stream_itr->first; 865 DVLOG(1) << "Failed to create a text stream.";
624 StreamParser::TrackId new_id = config_itr->first; 866 return false;
625 if (new_id != old_id) { 867 }
626 if (frame_processor_->UpdateTrack(old_id, new_id)) { 868
627 text_stream_map_.clear(); 869 if (!frame_processor_->AddTrack(track_info.track_id(), text_stream)) {
628 text_stream_map_[config_itr->first] = text_stream; 870 MEDIA_LOG(log_cb_) << "Failed to add text track ID "
629 } else { 871 << track_info.track_id()
630 success &= false; 872 << " to frame processor.";
631 MEDIA_LOG(log_cb_) << "Error remapping single text track number"; 873 return false;
632 } 874 }
633 } 875
634 } 876 text_stream->UpdateTextConfig(track_info.config(), log_cb_);
635 } else { 877 text_stream_map_[track_info.track_id()] = text_stream;
636 for (TextConfigItr config_itr = text_configs.begin(); 878 new_text_track_cb_.Run(text_stream, track_info.config());
637 config_itr != text_configs.end(); ++config_itr) { 879 }
638 TextStreamMap::iterator stream_itr = 880
639 text_stream_map_.find(config_itr->first); 881 return true;
640 if (stream_itr == text_stream_map_.end()) {
641 success &= false;
642 MEDIA_LOG(log_cb_) << "Unexpected text track configuration "
643 "for track ID "
644 << config_itr->first;
645 break;
646 }
647
648 const TextTrackConfig& new_config = config_itr->second;
649 ChunkDemuxerStream* stream = stream_itr->second;
650 TextTrackConfig old_config = stream->text_track_config();
651 if (!new_config.Matches(old_config)) {
652 success &= false;
653 MEDIA_LOG(log_cb_) << "New text track config for track ID "
654 << config_itr->first
655 << " does not match old one.";
656 break;
657 }
658 }
659 }
660 }
661
662 frame_processor_->SetAllTrackBuffersNeedRandomAccessPoint();
663
664 DVLOG(1) << "OnNewConfigs() : " << (success ? "success" : "failed");
665 return success;
666 } 882 }
667 883
668 void SourceState::OnNewMediaSegment() { 884 void SourceState::OnNewMediaSegment() {
669 DVLOG(2) << "OnNewMediaSegment()"; 885 DVLOG(2) << "OnNewMediaSegment()";
670 parsing_media_segment_ = true; 886 parsing_media_segment_ = true;
671 new_media_segment_ = true; 887 new_media_segment_ = true;
672 } 888 }
673 889
674 void SourceState::OnEndOfMediaSegment() { 890 void SourceState::OnEndOfMediaSegment() {
675 DVLOG(2) << "OnEndOfMediaSegment()"; 891 DVLOG(2) << "OnEndOfMediaSegment()";
(...skipping 461 matching lines...) Expand 10 before | Expand all | Expand 10 after
1137 SeekAllSources(seek_time); 1353 SeekAllSources(seek_time);
1138 1354
1139 if (seek_cb_.is_null()) { 1355 if (seek_cb_.is_null()) {
1140 cancel_next_seek_ = true; 1356 cancel_next_seek_ = true;
1141 return; 1357 return;
1142 } 1358 }
1143 1359
1144 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); 1360 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
1145 } 1361 }
1146 1362
1147 ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id, 1363 ChunkDemuxer::Status ChunkDemuxer::AddId(
1148 const std::string& type, 1364 const std::string& id,
1149 std::vector<std::string>& codecs) { 1365 const std::string& type,
1366 std::vector<std::string>& codecs,
1367 const NewInitSegmentCB& new_init_segment_cb) {
1150 base::AutoLock auto_lock(lock_); 1368 base::AutoLock auto_lock(lock_);
1151 1369
1152 if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || IsValidId(id)) 1370 if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || IsValidId(id))
1153 return kReachedIdLimit; 1371 return kReachedIdLimit;
1154 1372
1155 bool has_audio = false; 1373 bool has_audio = false;
1156 bool has_video = false; 1374 bool has_video = false;
1157 scoped_ptr<media::StreamParser> stream_parser( 1375 scoped_ptr<media::StreamParser> stream_parser(
1158 StreamParserFactory::Create(type, codecs, log_cb_, 1376 StreamParserFactory::Create(type, codecs, log_cb_,
1159 &has_audio, &has_video)); 1377 &has_audio, &has_video));
(...skipping 11 matching lines...) Expand all
1171 if (has_video) 1389 if (has_video)
1172 source_id_video_ = id; 1390 source_id_video_ = id;
1173 1391
1174 scoped_ptr<FrameProcessor> frame_processor( 1392 scoped_ptr<FrameProcessor> frame_processor(
1175 new FrameProcessor(base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary, 1393 new FrameProcessor(base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary,
1176 base::Unretained(this)))); 1394 base::Unretained(this))));
1177 1395
1178 scoped_ptr<SourceState> source_state( 1396 scoped_ptr<SourceState> source_state(
1179 new SourceState(stream_parser.Pass(), 1397 new SourceState(stream_parser.Pass(),
1180 frame_processor.Pass(), log_cb_, 1398 frame_processor.Pass(), log_cb_,
1399 new_init_segment_cb,
1181 base::Bind(&ChunkDemuxer::CreateDemuxerStream, 1400 base::Bind(&ChunkDemuxer::CreateDemuxerStream,
1182 base::Unretained(this)))); 1401 base::Unretained(this))));
1183 1402
1184 SourceState::NewTextTrackCB new_text_track_cb; 1403 SourceState::NewTextTrackCB new_text_track_cb;
1185 1404
1186 if (enable_text_) { 1405 if (enable_text_) {
1187 new_text_track_cb = base::Bind(&ChunkDemuxer::OnNewTextTrack, 1406 new_text_track_cb = base::Bind(&ChunkDemuxer::OnNewTextTrack,
1188 base::Unretained(this)); 1407 base::Unretained(this));
1189 } 1408 }
1190 1409
(...skipping 548 matching lines...) Expand 10 before | Expand all | Expand 10 after
1739 } 1958 }
1740 1959
1741 void ChunkDemuxer::ShutdownAllStreams() { 1960 void ChunkDemuxer::ShutdownAllStreams() {
1742 for (SourceStateMap::iterator itr = source_state_map_.begin(); 1961 for (SourceStateMap::iterator itr = source_state_map_.begin();
1743 itr != source_state_map_.end(); ++itr) { 1962 itr != source_state_map_.end(); ++itr) {
1744 itr->second->Shutdown(); 1963 itr->second->Shutdown();
1745 } 1964 }
1746 } 1965 }
1747 1966
1748 } // namespace media 1967 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/chunk_demuxer.h ('k') | media/filters/chunk_demuxer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698