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

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

Issue 191513002: Extract coded frame processing from SourceState into LegacyFrameProcessor (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix some lint errors Created 6 years, 9 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
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 <deque>
9 #include <limits> 8 #include <limits>
10 #include <list> 9 #include <list>
11 10
12 #include "base/bind.h" 11 #include "base/bind.h"
13 #include "base/callback_helpers.h" 12 #include "base/callback_helpers.h"
14 #include "base/location.h" 13 #include "base/location.h"
15 #include "base/message_loop/message_loop_proxy.h" 14 #include "base/message_loop/message_loop_proxy.h"
16 #include "base/stl_util.h" 15 #include "base/stl_util.h"
17 #include "media/base/audio_decoder_config.h" 16 #include "media/base/audio_decoder_config.h"
18 #include "media/base/bind_to_current_loop.h" 17 #include "media/base/bind_to_current_loop.h"
19 #include "media/base/stream_parser_buffer.h" 18 #include "media/base/stream_parser_buffer.h"
20 #include "media/base/video_decoder_config.h" 19 #include "media/base/video_decoder_config.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 // List of time ranges for each SourceBuffer. 27 // List of time ranges for each SourceBuffer.
28 typedef std::list<Ranges<TimeDelta> > RangesList; 28 typedef std::list<Ranges<TimeDelta> > RangesList;
29 static Ranges<TimeDelta> ComputeIntersection(const RangesList& activeRanges, 29 static Ranges<TimeDelta> ComputeIntersection(const RangesList& activeRanges,
30 bool ended) { 30 bool ended) {
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
79 return intersection_ranges; 79 return intersection_ranges;
80 } 80 }
81 81
82 // Contains state belonging to a source id. 82 // Contains state belonging to a source id.
83 class SourceState { 83 class SourceState {
84 public: 84 public:
85 // Callback signature used to create ChunkDemuxerStreams. 85 // Callback signature used to create ChunkDemuxerStreams.
86 typedef base::Callback<ChunkDemuxerStream*( 86 typedef base::Callback<ChunkDemuxerStream*(
87 DemuxerStream::Type)> CreateDemuxerStreamCB; 87 DemuxerStream::Type)> CreateDemuxerStreamCB;
88 88
89 // Callback signature used to notify ChunkDemuxer of timestamps
90 // that may cause the duration to be updated.
91 typedef base::Callback<void(
92 TimeDelta, ChunkDemuxerStream*)> IncreaseDurationCB;
93
94 typedef base::Callback<void( 89 typedef base::Callback<void(
95 ChunkDemuxerStream*, const TextTrackConfig&)> NewTextTrackCB; 90 ChunkDemuxerStream*, const TextTrackConfig&)> NewTextTrackCB;
96 91
97 SourceState(scoped_ptr<StreamParser> stream_parser, const LogCB& log_cb, 92 SourceState(
98 const CreateDemuxerStreamCB& create_demuxer_stream_cb, 93 scoped_ptr<StreamParser> stream_parser,
99 const IncreaseDurationCB& increase_duration_cb); 94 scoped_ptr<FrameProcessorBase> frame_processor, const LogCB& log_cb,
95 const CreateDemuxerStreamCB& create_demuxer_stream_cb);
100 96
101 ~SourceState(); 97 ~SourceState();
102 98
103 void Init(const StreamParser::InitCB& init_cb, 99 void Init(const StreamParser::InitCB& init_cb,
104 bool allow_audio, 100 bool allow_audio,
105 bool allow_video, 101 bool allow_video,
106 const StreamParser::NeedKeyCB& need_key_cb, 102 const StreamParser::NeedKeyCB& need_key_cb,
107 const NewTextTrackCB& new_text_track_cb); 103 const NewTextTrackCB& new_text_track_cb);
108 104
109 // Appends new data to the StreamParser. 105 // Appends new data to the StreamParser.
110 // Returns true if the data was successfully appended. Returns false if an 106 // Returns true if the data was successfully appended. Returns false if an
111 // error occurred. Appending uses cached |timestamp_offset_| and may update 107 // error occurred. Append processing in the |frame_processor_| uses a cached
acolwell GONE FROM CHROMIUM 2014/03/08 21:15:51 nit: Why don't we just have the frame processor us
wolenetz 2014/03/10 23:03:47 Good point. Done: I've updated to cache the offset
112 // |*timestamp_offset| if |timestamp_offset| is not NULL. 108 // timestamp offset. If that processing updates the offset, this method will
113 // TODO(wolenetz): Rework so |timestamp_offset_| is only valid during 109 // update |*timestamp_offset| if |timestamp_offset| is not NULL.
114 // Append(). See http://crbug.com/347623.
115 bool Append(const uint8* data, size_t length, double* timestamp_offset); 110 bool Append(const uint8* data, size_t length, double* timestamp_offset);
116 111
117 // Aborts the current append sequence and resets the parser. 112 // Aborts the current append sequence and resets the parser.
118 void Abort(); 113 void Abort();
119 114
120 // Calls Remove(|start|, |end|, |duration|) on all 115 // Calls Remove(|start|, |end|, |duration|) on all
121 // ChunkDemuxerStreams managed by this object. 116 // ChunkDemuxerStreams managed by this object.
122 void Remove(TimeDelta start, TimeDelta end, TimeDelta duration); 117 void Remove(TimeDelta start, TimeDelta end, TimeDelta duration);
123 118
124 // Sets user-specified |timestamp_offset_| if possible. 119 // Informs the |frame_processor_| of the user-specified offset, if possible.
125 // Returns true if the offset was set. Returns false if the offset could not 120 // Returns true if the offset was set. Returns false if the offset could not
126 // be set at this time. 121 // be set at this time because parsing is in the middle of a media segment.
127 bool SetTimestampOffset(TimeDelta timestamp_offset); 122 bool SetTimestampOffset(TimeDelta timestamp_offset);
128 123
129 // Sets |sequence_mode_| to |sequence_mode| if possible. 124 // Sets |frame_processor_|'s sequence mode to |sequence_mode| if possible.
130 // Returns true if the mode update was allowed. Returns false if the mode 125 // Returns true if the mode update was allowed. Returns false if the mode
131 // could not be updated at this time. 126 // could not be updated at this time.
132 bool SetSequenceMode(bool sequence_mode); 127 bool SetSequenceMode(bool sequence_mode);
133 128
134 void set_append_window_start(TimeDelta start) { 129 void SetAppendWindowStart(TimeDelta start);
135 append_window_start_ = start; 130 void SetAppendWindowEnd(TimeDelta end);
136 }
137 void set_append_window_end(TimeDelta end) { append_window_end_ = end; }
138 131
139 // Returns the range of buffered data in this source, capped at |duration|. 132 // Returns the range of buffered data in this source, capped at |duration|.
140 // |ended| - Set to true if end of stream has been signalled and the special 133 // |ended| - Set to true if end of stream has been signalled and the special
141 // end of stream range logic needs to be executed. 134 // end of stream range logic needs to be executed.
142 Ranges<TimeDelta> GetBufferedRanges(TimeDelta duration, bool ended) const; 135 Ranges<TimeDelta> GetBufferedRanges(TimeDelta duration, bool ended) const;
143 136
144 // Returns the highest buffered duration across all streams managed 137 // Returns the highest buffered duration across all streams managed
145 // by this object. 138 // by this object.
146 // Returns TimeDelta() if none of the streams contain buffered data. 139 // Returns TimeDelta() if none of the streams contain buffered data.
147 TimeDelta GetMaxBufferedDuration() const; 140 TimeDelta GetMaxBufferedDuration() const;
(...skipping 22 matching lines...) Expand all
170 const AudioDecoderConfig& audio_config, 163 const AudioDecoderConfig& audio_config,
171 const VideoDecoderConfig& video_config, 164 const VideoDecoderConfig& video_config,
172 const StreamParser::TextTrackConfigMap& text_configs); 165 const StreamParser::TextTrackConfigMap& text_configs);
173 166
174 // Called by the |stream_parser_| at the beginning of a new media segment. 167 // Called by the |stream_parser_| at the beginning of a new media segment.
175 void OnNewMediaSegment(); 168 void OnNewMediaSegment();
176 169
177 // Called by the |stream_parser_| at the end of a media segment. 170 // Called by the |stream_parser_| at the end of a media segment.
178 void OnEndOfMediaSegment(); 171 void OnEndOfMediaSegment();
179 172
180 // Called by the |stream_parser_| when new buffers have been parsed. It 173 // Called by the |stream_parser_| when new buffers have been parsed.
181 // applies |timestamp_offset_| to all buffers in |audio_buffers|, 174 // It processes the new buffers using |frame_processor_|, which includes
182 // |video_buffers| and |text_map| and then calls Append() with the modified 175 // appending the processed frames to associated demuxer streams for each
183 // buffers on |audio_|, |video_| and/or the text demuxer streams associated 176 // frame's track.
184 // with the track numbers in |text_map|.
185 // Returns true on a successful call. Returns false if an error occurred while 177 // Returns true on a successful call. Returns false if an error occurred while
186 // processing the buffers. 178 // processing the buffers.
187 bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers, 179 bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers,
188 const StreamParser::BufferQueue& video_buffers, 180 const StreamParser::BufferQueue& video_buffers,
189 const StreamParser::TextBufferQueueMap& text_map); 181 const StreamParser::TextBufferQueueMap& text_map);
190 182
191 // Helper function for OnNewBuffers() when new text buffers have been parsed.
192 // It applies |timestamp_offset_| to all buffers in |buffers| and then appends
193 // the (modified) buffers to the demuxer stream associated with
194 // the track having |text_track_id|.
195 // Returns true on a successful call. Returns false if an error occurred while
196 // processing the buffers.
197 bool OnTextBuffers(StreamParser::TrackId text_track_id,
198 const StreamParser::BufferQueue& buffers);
199
200 // Helper function that appends |buffers| to |stream| and calls
201 // |increase_duration_cb_| to potentially update the duration.
202 // Returns true if the append was successful. Returns false if
203 // |stream| is NULL or something in |buffers| caused the append to fail.
204 bool AppendAndUpdateDuration(ChunkDemuxerStream* stream,
205 const StreamParser::BufferQueue& buffers);
206
207 // Helper function that adds |timestamp_offset_| to each buffer in |buffers|.
208 void AdjustBufferTimestamps(const StreamParser::BufferQueue& buffers);
209
210 // Filters out buffers that are outside of the append window
211 // [|append_window_start_|, |append_window_end_|).
212 // |needs_keyframe| is a pointer to the |xxx_need_keyframe_| flag
213 // associated with the |buffers|. Its state is read an updated as
214 // this method filters |buffers|.
215 // Buffers that are inside the append window are appended to the end
216 // of |filtered_buffers|.
217 void FilterWithAppendWindow(const StreamParser::BufferQueue& buffers,
218 bool* needs_keyframe,
219 StreamParser::BufferQueue* filtered_buffers);
220
221 CreateDemuxerStreamCB create_demuxer_stream_cb_; 183 CreateDemuxerStreamCB create_demuxer_stream_cb_;
222 IncreaseDurationCB increase_duration_cb_;
223 NewTextTrackCB new_text_track_cb_; 184 NewTextTrackCB new_text_track_cb_;
224 185
225 // The offset to apply to media segment timestamps. 186 // During Append(), if OnNewBuffers() coded frame processing updates the
226 TimeDelta timestamp_offset_; 187 // timestamp offset and if |timestamp_offset_during_append_| is not NULL,
227 188 // then |*timestamp_offset_during_append_| is also updated so Append()'s
228 // Flag that tracks whether or not the current Append() operation changed 189 // caller can know the new offset.
229 // |timestamp_offset_|. 190 double* timestamp_offset_during_append_;
230 bool timestamp_offset_updated_by_append_;
231
232 // Tracks the mode by which appended media is processed. If true, then
233 // appended media is processed using "sequence" mode. Otherwise, appended
234 // media is processed using "segments" mode.
235 // TODO(wolenetz): Enable "sequence" mode logic. See http://crbug.com/249422
236 // and http://crbug.com/333437.
237 bool sequence_mode_;
238
239 TimeDelta append_window_start_;
240 TimeDelta append_window_end_;
241 191
242 // Set to true if the next buffers appended within the append window 192 // Set to true if the next buffers appended within the append window
243 // represent the start of a new media segment. This flag being set 193 // represent the start of a new media segment. This flag being set
244 // triggers a call to |new_segment_cb_| when the new buffers are 194 // triggers a call to |new_segment_cb_| when the new buffers are
245 // appended. The flag is set on actual media segment boundaries and 195 // appended. The flag is set on actual media segment boundaries and
246 // when the "append window" filtering causes discontinuities in the 196 // when the "append window" filtering causes discontinuities in the
247 // appended data. 197 // appended data.
248 bool new_media_segment_; 198 bool new_media_segment_;
249 199
250 // Keeps track of whether |timestamp_offset_| or |sequence_mode_| can be 200 // Keeps track of whether SetTimestampOffset() or SetSequenceMode() are
251 // updated. These cannot be updated if a media segment is being parsed. 201 // allowed. These are disallowed if a media segment is being parsed.
252 bool parsing_media_segment_; 202 bool parsing_media_segment_;
253 203
254 // The object used to parse appended data. 204 // The object used to parse appended data.
255 scoped_ptr<StreamParser> stream_parser_; 205 scoped_ptr<StreamParser> stream_parser_;
256 206
257 ChunkDemuxerStream* audio_; 207 ChunkDemuxerStream* audio_; // Not owned by |this|.
258 bool audio_needs_keyframe_; 208 ChunkDemuxerStream* video_; // Not owned by |this|.
259
260 ChunkDemuxerStream* video_;
261 bool video_needs_keyframe_;
262 209
263 typedef std::map<StreamParser::TrackId, ChunkDemuxerStream*> TextStreamMap; 210 typedef std::map<StreamParser::TrackId, ChunkDemuxerStream*> TextStreamMap;
264 TextStreamMap text_stream_map_; 211 TextStreamMap text_stream_map_; // |this| owns the map's stream pointers.
265 212
213 scoped_ptr<FrameProcessorBase> frame_processor_;
266 LogCB log_cb_; 214 LogCB log_cb_;
267 215
268 DISALLOW_COPY_AND_ASSIGN(SourceState); 216 DISALLOW_COPY_AND_ASSIGN(SourceState);
269 }; 217 };
270 218
271 class ChunkDemuxerStream : public DemuxerStream { 219 SourceState::SourceState(
272 public: 220 scoped_ptr<StreamParser> stream_parser,
273 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; 221 scoped_ptr<FrameProcessorBase> frame_processor,
274 222 const LogCB& log_cb,
275 explicit ChunkDemuxerStream(Type type); 223 const CreateDemuxerStreamCB& create_demuxer_stream_cb)
276 virtual ~ChunkDemuxerStream();
277
278 // ChunkDemuxerStream control methods.
279 void StartReturningData();
280 void AbortReads();
281 void CompletePendingReadIfPossible();
282 void Shutdown();
283
284 // SourceBufferStream manipulation methods.
285 void Seek(TimeDelta time);
286 bool IsSeekWaitingForData() const;
287
288 // Add buffers to this stream. Buffers are stored in SourceBufferStreams,
289 // which handle ordering and overlap resolution.
290 // Returns true if buffers were successfully added.
291 bool Append(const StreamParser::BufferQueue& buffers);
292
293 // Removes buffers between |start| and |end| according to the steps
294 // in the "Coded Frame Removal Algorithm" in the Media Source
295 // Extensions Spec.
296 // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-sourc e.html#sourcebuffer-coded-frame-removal
297 //
298 // |duration| is the current duration of the presentation. It is
299 // required by the computation outlined in the spec.
300 void Remove(TimeDelta start, TimeDelta end, TimeDelta duration);
301
302 // Signal to the stream that duration has changed to |duration|.
303 void OnSetDuration(TimeDelta duration);
304
305 // Returns the range of buffered data in this stream, capped at |duration|.
306 Ranges<TimeDelta> GetBufferedRanges(TimeDelta duration) const;
307
308 // Returns the duration of the buffered data.
309 // Returns TimeDelta() if the stream has no buffered data.
310 TimeDelta GetBufferedDuration() const;
311
312 // Signal to the stream that buffers handed in through subsequent calls to
313 // Append() belong to a media segment that starts at |start_timestamp|.
314 void OnNewMediaSegment(TimeDelta start_timestamp);
315
316 // Called when midstream config updates occur.
317 // Returns true if the new config is accepted.
318 // Returns false if the new config should trigger an error.
319 bool UpdateAudioConfig(const AudioDecoderConfig& config, const LogCB& log_cb);
320 bool UpdateVideoConfig(const VideoDecoderConfig& config, const LogCB& log_cb);
321 void UpdateTextConfig(const TextTrackConfig& config, const LogCB& log_cb);
322
323 void MarkEndOfStream();
324 void UnmarkEndOfStream();
325
326 // DemuxerStream methods.
327 virtual void Read(const ReadCB& read_cb) OVERRIDE;
328 virtual Type type() OVERRIDE;
329 virtual void EnableBitstreamConverter() OVERRIDE;
330 virtual AudioDecoderConfig audio_decoder_config() OVERRIDE;
331 virtual VideoDecoderConfig video_decoder_config() OVERRIDE;
332
333 // Returns the text track configuration. It is an error to call this method
334 // if type() != TEXT.
335 TextTrackConfig text_track_config();
336
337 // Sets the memory limit, in bytes, on the SourceBufferStream.
338 void set_memory_limit_for_testing(int memory_limit) {
339 stream_->set_memory_limit_for_testing(memory_limit);
340 }
341
342 private:
343 enum State {
344 UNINITIALIZED,
345 RETURNING_DATA_FOR_READS,
346 RETURNING_ABORT_FOR_READS,
347 SHUTDOWN,
348 };
349
350 // Assigns |state_| to |state|
351 void ChangeState_Locked(State state);
352
353 void CompletePendingReadIfPossible_Locked();
354
355 // Specifies the type of the stream.
356 Type type_;
357
358 scoped_ptr<SourceBufferStream> stream_;
359
360 mutable base::Lock lock_;
361 State state_;
362 ReadCB read_cb_;
363
364 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream);
365 };
366
367 SourceState::SourceState(scoped_ptr<StreamParser> stream_parser,
368 const LogCB& log_cb,
369 const CreateDemuxerStreamCB& create_demuxer_stream_cb,
370 const IncreaseDurationCB& increase_duration_cb)
371 : create_demuxer_stream_cb_(create_demuxer_stream_cb), 224 : create_demuxer_stream_cb_(create_demuxer_stream_cb),
372 increase_duration_cb_(increase_duration_cb), 225 timestamp_offset_during_append_(NULL),
373 timestamp_offset_updated_by_append_(false),
374 sequence_mode_(false),
375 append_window_end_(kInfiniteDuration()),
376 new_media_segment_(false), 226 new_media_segment_(false),
377 parsing_media_segment_(false), 227 parsing_media_segment_(false),
378 stream_parser_(stream_parser.release()), 228 stream_parser_(stream_parser.release()),
379 audio_(NULL), 229 audio_(NULL),
380 audio_needs_keyframe_(true),
381 video_(NULL), 230 video_(NULL),
382 video_needs_keyframe_(true), 231 frame_processor_(frame_processor.release()),
383 log_cb_(log_cb) { 232 log_cb_(log_cb) {
384 DCHECK(!create_demuxer_stream_cb_.is_null()); 233 DCHECK(!create_demuxer_stream_cb_.is_null());
385 DCHECK(!increase_duration_cb_.is_null()); 234 DCHECK(frame_processor_);
386 } 235 }
387 236
388 SourceState::~SourceState() { 237 SourceState::~SourceState() {
389 Shutdown(); 238 Shutdown();
390 239
391 STLDeleteValues(&text_stream_map_); 240 STLDeleteValues(&text_stream_map_);
392 } 241 }
393 242
394 void SourceState::Init(const StreamParser::InitCB& init_cb, 243 void SourceState::Init(const StreamParser::InitCB& init_cb,
395 bool allow_audio, 244 bool allow_audio,
(...skipping 15 matching lines...) Expand all
411 base::Unretained(this)), 260 base::Unretained(this)),
412 base::Bind(&SourceState::OnEndOfMediaSegment, 261 base::Bind(&SourceState::OnEndOfMediaSegment,
413 base::Unretained(this)), 262 base::Unretained(this)),
414 log_cb_); 263 log_cb_);
415 } 264 }
416 265
417 bool SourceState::SetTimestampOffset(TimeDelta timestamp_offset) { 266 bool SourceState::SetTimestampOffset(TimeDelta timestamp_offset) {
418 if (parsing_media_segment_) 267 if (parsing_media_segment_)
419 return false; 268 return false;
420 269
421 timestamp_offset_ = timestamp_offset; 270 frame_processor_->SetTimestampOffset(timestamp_offset);
422 return true; 271 return true;
423 } 272 }
424 273
425 bool SourceState::SetSequenceMode(bool sequence_mode) { 274 bool SourceState::SetSequenceMode(bool sequence_mode) {
426 if (parsing_media_segment_) 275 if (parsing_media_segment_)
427 return false; 276 return false;
428 277
429 sequence_mode_ = sequence_mode; 278 frame_processor_->SetSequenceMode(sequence_mode);
430 return true; 279 return true;
431 } 280 }
432 281
282 void SourceState::SetAppendWindowStart(TimeDelta start) {
283 frame_processor_->set_append_window_start(start);
284 }
285
286 void SourceState::SetAppendWindowEnd(TimeDelta end) {
287 frame_processor_->set_append_window_end(end);
288 }
289
433 bool SourceState::Append(const uint8* data, size_t length, 290 bool SourceState::Append(const uint8* data, size_t length,
434 double* timestamp_offset) { 291 double* timestamp_offset) {
435 timestamp_offset_updated_by_append_ = false; 292 timestamp_offset_during_append_ = timestamp_offset;
436 bool err = stream_parser_->Parse(data, length); 293 bool err = stream_parser_->Parse(data, length);
437 294 timestamp_offset_during_append_ = NULL;
438 if (timestamp_offset_updated_by_append_ && timestamp_offset)
439 *timestamp_offset = timestamp_offset_.InSecondsF();
440
441 return err; 295 return err;
442 } 296 }
443 297
444 void SourceState::Abort() { 298 void SourceState::Abort() {
445 stream_parser_->Flush(); 299 stream_parser_->Flush();
446 audio_needs_keyframe_ = true; 300 frame_processor_->Reset();
447 video_needs_keyframe_ = true;
448 parsing_media_segment_ = false; 301 parsing_media_segment_ = false;
449 } 302 }
450 303
451 void SourceState::Remove(TimeDelta start, TimeDelta end, TimeDelta duration) { 304 void SourceState::Remove(TimeDelta start, TimeDelta end, TimeDelta duration) {
452 if (audio_) 305 if (audio_)
453 audio_->Remove(start, end, duration); 306 audio_->Remove(start, end, duration);
454 307
455 if (video_) 308 if (video_)
456 video_->Remove(start, end, duration); 309 video_->Remove(start, end, duration);
457 310
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
624 // NOTE: We are intentionally not checking the text tracks 477 // NOTE: We are intentionally not checking the text tracks
625 // because text tracks are discontinuous and may not have data 478 // because text tracks are discontinuous and may not have data
626 // for the seek position. This is ok and playback should not be 479 // for the seek position. This is ok and playback should not be
627 // stalled because we don't have cues. If cues, with timestamps after 480 // stalled because we don't have cues. If cues, with timestamps after
628 // the seek time, eventually arrive they will be delivered properly 481 // the seek time, eventually arrive they will be delivered properly
629 // in response to ChunkDemuxerStream::Read() calls. 482 // in response to ChunkDemuxerStream::Read() calls.
630 483
631 return false; 484 return false;
632 } 485 }
633 486
634 void SourceState::AdjustBufferTimestamps(
635 const StreamParser::BufferQueue& buffers) {
636 if (timestamp_offset_ == TimeDelta())
637 return;
638
639 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin();
640 itr != buffers.end(); ++itr) {
641 (*itr)->SetDecodeTimestamp(
642 (*itr)->GetDecodeTimestamp() + timestamp_offset_);
643 (*itr)->set_timestamp((*itr)->timestamp() + timestamp_offset_);
644 }
645 }
646
647 bool SourceState::OnNewConfigs( 487 bool SourceState::OnNewConfigs(
648 bool allow_audio, bool allow_video, 488 bool allow_audio, bool allow_video,
649 const AudioDecoderConfig& audio_config, 489 const AudioDecoderConfig& audio_config,
650 const VideoDecoderConfig& video_config, 490 const VideoDecoderConfig& video_config,
651 const StreamParser::TextTrackConfigMap& text_configs) { 491 const StreamParser::TextTrackConfigMap& text_configs) {
652 DVLOG(1) << "OnNewConfigs(" << allow_audio << ", " << allow_video 492 DVLOG(1) << "OnNewConfigs(" << allow_audio << ", " << allow_video
653 << ", " << audio_config.IsValidConfig() 493 << ", " << audio_config.IsValidConfig()
654 << ", " << video_config.IsValidConfig() << ")"; 494 << ", " << video_config.IsValidConfig() << ")";
655 495
656 if (!audio_config.IsValidConfig() && !video_config.IsValidConfig()) { 496 if (!audio_config.IsValidConfig() && !video_config.IsValidConfig()) {
(...skipping 25 matching lines...) Expand all
682 522
683 bool success = true; 523 bool success = true;
684 if (audio_config.IsValidConfig()) { 524 if (audio_config.IsValidConfig()) {
685 if (!audio_) { 525 if (!audio_) {
686 audio_ = create_demuxer_stream_cb_.Run(DemuxerStream::AUDIO); 526 audio_ = create_demuxer_stream_cb_.Run(DemuxerStream::AUDIO);
687 527
688 if (!audio_) { 528 if (!audio_) {
689 DVLOG(1) << "Failed to create an audio stream."; 529 DVLOG(1) << "Failed to create an audio stream.";
690 return false; 530 return false;
691 } 531 }
532
533 if (!frame_processor_->AddTrack(FrameProcessorBase::kAudioTrackId,
534 audio_)) {
535 DVLOG(1) << "Failed to add audio track to frame processor.";
536 return false;
537 }
692 } 538 }
693 539
694 success &= audio_->UpdateAudioConfig(audio_config, log_cb_); 540 success &= audio_->UpdateAudioConfig(audio_config, log_cb_);
695 } 541 }
696 542
697 if (video_config.IsValidConfig()) { 543 if (video_config.IsValidConfig()) {
698 if (!video_) { 544 if (!video_) {
699 video_ = create_demuxer_stream_cb_.Run(DemuxerStream::VIDEO); 545 video_ = create_demuxer_stream_cb_.Run(DemuxerStream::VIDEO);
700 546
701 if (!video_) { 547 if (!video_) {
702 DVLOG(1) << "Failed to create a video stream."; 548 DVLOG(1) << "Failed to create a video stream.";
703 return false; 549 return false;
704 } 550 }
551
552 if (!frame_processor_->AddTrack(FrameProcessorBase::kVideoTrackId,
553 video_)) {
554 DVLOG(1) << "Failed to add video track to frame processor.";
555 return false;
556 }
705 } 557 }
706 558
707 success &= video_->UpdateVideoConfig(video_config, log_cb_); 559 success &= video_->UpdateVideoConfig(video_config, log_cb_);
708 } 560 }
709 561
710 typedef StreamParser::TextTrackConfigMap::const_iterator TextConfigItr; 562 typedef StreamParser::TextTrackConfigMap::const_iterator TextConfigItr;
711 if (text_stream_map_.empty()) { 563 if (text_stream_map_.empty()) {
712 for (TextConfigItr itr = text_configs.begin(); 564 for (TextConfigItr itr = text_configs.begin();
713 itr != text_configs.end(); ++itr) { 565 itr != text_configs.end(); ++itr) {
714 ChunkDemuxerStream* const text_stream = 566 ChunkDemuxerStream* const text_stream =
715 create_demuxer_stream_cb_.Run(DemuxerStream::TEXT); 567 create_demuxer_stream_cb_.Run(DemuxerStream::TEXT);
568 if (!frame_processor_->AddTrack(itr->first, text_stream)) {
569 success &= false;
570 MEDIA_LOG(log_cb_) << "Failed to add text track ID " << itr->first
571 << " to frame processor.";
572 break;
573 }
716 text_stream->UpdateTextConfig(itr->second, log_cb_); 574 text_stream->UpdateTextConfig(itr->second, log_cb_);
717 text_stream_map_[itr->first] = text_stream; 575 text_stream_map_[itr->first] = text_stream;
718 new_text_track_cb_.Run(text_stream, itr->second); 576 new_text_track_cb_.Run(text_stream, itr->second);
719 } 577 }
720 } else { 578 } else {
721 const size_t text_count = text_stream_map_.size(); 579 const size_t text_count = text_stream_map_.size();
722 if (text_configs.size() != text_count) { 580 if (text_configs.size() != text_count) {
723 success &= false; 581 success &= false;
724 MEDIA_LOG(log_cb_) << "The number of text track configs changed."; 582 MEDIA_LOG(log_cb_) << "The number of text track configs changed.";
725 } else if (text_count == 1) { 583 } else if (text_count == 1) {
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
775 void SourceState::OnEndOfMediaSegment() { 633 void SourceState::OnEndOfMediaSegment() {
776 DVLOG(2) << "OnEndOfMediaSegment()"; 634 DVLOG(2) << "OnEndOfMediaSegment()";
777 parsing_media_segment_ = false; 635 parsing_media_segment_ = false;
778 new_media_segment_ = false; 636 new_media_segment_ = false;
779 } 637 }
780 638
781 bool SourceState::OnNewBuffers( 639 bool SourceState::OnNewBuffers(
782 const StreamParser::BufferQueue& audio_buffers, 640 const StreamParser::BufferQueue& audio_buffers,
783 const StreamParser::BufferQueue& video_buffers, 641 const StreamParser::BufferQueue& video_buffers,
784 const StreamParser::TextBufferQueueMap& text_map) { 642 const StreamParser::TextBufferQueueMap& text_map) {
785 DCHECK(!audio_buffers.empty() || !video_buffers.empty() || 643 DVLOG(2) << "OnNewBuffers()";
786 !text_map.empty());
787 644
788 // TODO(wolenetz): DCHECK + return false if any of these buffers have UNKNOWN 645 return frame_processor_->MergeQueuesAndProcessFrames(
789 // type() in upcoming coded frame processing compliant implementation. See 646 audio_buffers, video_buffers, text_map, &new_media_segment_,
790 // http://crbug.com/249422. 647 timestamp_offset_during_append_);
acolwell GONE FROM CHROMIUM 2014/03/08 21:15:51 nit: I think you should just pass the append windo
wolenetz 2014/03/10 23:03:47 Done and done.
791
792 AdjustBufferTimestamps(audio_buffers);
793 AdjustBufferTimestamps(video_buffers);
794
795 StreamParser::BufferQueue filtered_audio;
796 StreamParser::BufferQueue filtered_video;
797
798 FilterWithAppendWindow(audio_buffers, &audio_needs_keyframe_,
799 &filtered_audio);
800
801 FilterWithAppendWindow(video_buffers, &video_needs_keyframe_,
802 &filtered_video);
803
804 if ((!filtered_audio.empty() || !filtered_video.empty()) &&
805 new_media_segment_) {
806 // Find the earliest timestamp in the filtered buffers and use that for the
807 // segment start timestamp.
808 TimeDelta segment_timestamp = kNoTimestamp();
809
810 if (!filtered_audio.empty())
811 segment_timestamp = filtered_audio.front()->GetDecodeTimestamp();
812
813 if (!filtered_video.empty() &&
814 (segment_timestamp == kNoTimestamp() ||
815 filtered_video.front()->GetDecodeTimestamp() < segment_timestamp)) {
816 segment_timestamp = filtered_video.front()->GetDecodeTimestamp();
817 }
818
819 new_media_segment_ = false;
820
821 if (audio_)
822 audio_->OnNewMediaSegment(segment_timestamp);
823
824 if (video_)
825 video_->OnNewMediaSegment(segment_timestamp);
826
827 for (TextStreamMap::iterator itr = text_stream_map_.begin();
828 itr != text_stream_map_.end(); ++itr) {
829 itr->second->OnNewMediaSegment(segment_timestamp);
830 }
831 }
832
833 if (!filtered_audio.empty() &&
834 !AppendAndUpdateDuration(audio_, filtered_audio)) {
835 return false;
836 }
837
838 if (!filtered_video.empty() &&
839 !AppendAndUpdateDuration(video_, filtered_video)) {
840 return false;
841 }
842
843 if (text_map.empty())
844 return true;
845
846 // Process any buffers for each of the text tracks in the map.
847 bool all_text_buffers_empty = true;
848 for (StreamParser::TextBufferQueueMap::const_iterator itr = text_map.begin();
849 itr != text_map.end();
850 ++itr) {
851 const StreamParser::BufferQueue text_buffers = itr->second;
852 if (!text_buffers.empty()) {
853 all_text_buffers_empty = false;
854 if (!OnTextBuffers(itr->first, text_buffers))
855 return false;
856 }
857 }
858
859 DCHECK(!all_text_buffers_empty);
860 return true;
861 }
862
863 bool SourceState::OnTextBuffers(
864 StreamParser::TrackId text_track_id,
865 const StreamParser::BufferQueue& buffers) {
866 DCHECK(!buffers.empty());
867
868 TextStreamMap::iterator itr = text_stream_map_.find(text_track_id);
869 if (itr == text_stream_map_.end())
870 return false;
871
872 AdjustBufferTimestamps(buffers);
873
874 StreamParser::BufferQueue filtered_buffers;
875 bool needs_keyframe = false;
876 FilterWithAppendWindow(buffers, &needs_keyframe, &filtered_buffers);
877
878 if (filtered_buffers.empty())
879 return true;
880
881 return AppendAndUpdateDuration(itr->second, filtered_buffers);
882 }
883
884 bool SourceState::AppendAndUpdateDuration(
885 ChunkDemuxerStream* stream,
886 const StreamParser::BufferQueue& buffers) {
887 DCHECK(!buffers.empty());
888
889 if (!stream || !stream->Append(buffers))
890 return false;
891
892 increase_duration_cb_.Run(buffers.back()->timestamp(), stream);
893 return true;
894 }
895
896 void SourceState::FilterWithAppendWindow(
897 const StreamParser::BufferQueue& buffers, bool* needs_keyframe,
898 StreamParser::BufferQueue* filtered_buffers) {
899 DCHECK(needs_keyframe);
900 DCHECK(filtered_buffers);
901
902 // This loop implements steps 1.9, 1.10, & 1.11 of the "Coded frame
903 // processing loop" in the Media Source Extensions spec.
904 // These steps filter out buffers that are not within the "append
905 // window" and handles resyncing on the next random access point
906 // (i.e., next keyframe) if a buffer gets dropped.
907 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin();
908 itr != buffers.end(); ++itr) {
909 // Filter out buffers that are outside the append window. Anytime
910 // a buffer gets dropped we need to set |*needs_keyframe| to true
911 // because we can only resume decoding at keyframes.
912 TimeDelta presentation_timestamp = (*itr)->timestamp();
913
914 // TODO(acolwell): Change |frame_end_timestamp| value to
915 // |presentation_timestamp + (*itr)->duration()|, like the spec
916 // requires, once frame durations are actually present in all buffers.
917 TimeDelta frame_end_timestamp = presentation_timestamp;
918 if (presentation_timestamp < append_window_start_ ||
919 frame_end_timestamp > append_window_end_) {
920 DVLOG(1) << "Dropping buffer outside append window."
921 << " presentation_timestamp "
922 << presentation_timestamp.InSecondsF();
923 *needs_keyframe = true;
924
925 // This triggers a discontinuity so we need to treat the next frames
926 // appended within the append window as if they were the beginning of a
927 // new segment.
928 new_media_segment_ = true;
929 continue;
930 }
931
932 // If |*needs_keyframe| is true then filter out buffers until we
933 // encounter the next keyframe.
934 if (*needs_keyframe) {
935 if (!(*itr)->IsKeyframe()) {
936 DVLOG(1) << "Dropping non-keyframe. presentation_timestamp "
937 << presentation_timestamp.InSecondsF();
938 continue;
939 }
940
941 *needs_keyframe = false;
942 }
943
944 filtered_buffers->push_back(*itr);
945 }
946 } 648 }
947 649
948 ChunkDemuxerStream::ChunkDemuxerStream(Type type) 650 ChunkDemuxerStream::ChunkDemuxerStream(Type type)
949 : type_(type), 651 : type_(type),
950 state_(UNINITIALIZED) { 652 state_(UNINITIALIZED) {
951 } 653 }
952 654
953 void ChunkDemuxerStream::StartReturningData() { 655 void ChunkDemuxerStream::StartReturningData() {
954 DVLOG(1) << "ChunkDemuxerStream::StartReturningData()"; 656 DVLOG(1) << "ChunkDemuxerStream::StartReturningData()";
955 base::AutoLock auto_lock(lock_); 657 base::AutoLock auto_lock(lock_);
(...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after
1363 if ((has_audio && !source_id_audio_.empty()) || 1065 if ((has_audio && !source_id_audio_.empty()) ||
1364 (has_video && !source_id_video_.empty())) 1066 (has_video && !source_id_video_.empty()))
1365 return kReachedIdLimit; 1067 return kReachedIdLimit;
1366 1068
1367 if (has_audio) 1069 if (has_audio)
1368 source_id_audio_ = id; 1070 source_id_audio_ = id;
1369 1071
1370 if (has_video) 1072 if (has_video)
1371 source_id_video_ = id; 1073 source_id_video_ = id;
1372 1074
1075 scoped_ptr<FrameProcessorBase> frame_processor(new LegacyFrameProcessor(
1076 base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary,
1077 base::Unretained(this))));
1078
1373 scoped_ptr<SourceState> source_state( 1079 scoped_ptr<SourceState> source_state(
1374 new SourceState(stream_parser.Pass(), log_cb_, 1080 new SourceState(stream_parser.Pass(),
1081 frame_processor.Pass(), log_cb_,
1375 base::Bind(&ChunkDemuxer::CreateDemuxerStream, 1082 base::Bind(&ChunkDemuxer::CreateDemuxerStream,
1376 base::Unretained(this)),
1377 base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary,
1378 base::Unretained(this)))); 1083 base::Unretained(this))));
1379 1084
1380 SourceState::NewTextTrackCB new_text_track_cb; 1085 SourceState::NewTextTrackCB new_text_track_cb;
1381 1086
1382 if (enable_text_) { 1087 if (enable_text_) {
1383 new_text_track_cb = base::Bind(&ChunkDemuxer::OnNewTextTrack, 1088 new_text_track_cb = base::Bind(&ChunkDemuxer::OnNewTextTrack,
1384 base::Unretained(this)); 1089 base::Unretained(this));
1385 } 1090 }
1386 1091
1387 source_state->Init( 1092 source_state->Init(
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after
1633 itr->second->UnmarkEndOfStream(); 1338 itr->second->UnmarkEndOfStream();
1634 } 1339 }
1635 } 1340 }
1636 1341
1637 void ChunkDemuxer::SetAppendWindowStart(const std::string& id, 1342 void ChunkDemuxer::SetAppendWindowStart(const std::string& id,
1638 TimeDelta start) { 1343 TimeDelta start) {
1639 base::AutoLock auto_lock(lock_); 1344 base::AutoLock auto_lock(lock_);
1640 DVLOG(1) << "SetAppendWindowStart(" << id << ", " 1345 DVLOG(1) << "SetAppendWindowStart(" << id << ", "
1641 << start.InSecondsF() << ")"; 1346 << start.InSecondsF() << ")";
1642 CHECK(IsValidId(id)); 1347 CHECK(IsValidId(id));
1643 source_state_map_[id]->set_append_window_start(start); 1348 source_state_map_[id]->SetAppendWindowStart(start);
1644 } 1349 }
1645 1350
1646 void ChunkDemuxer::SetAppendWindowEnd(const std::string& id, TimeDelta end) { 1351 void ChunkDemuxer::SetAppendWindowEnd(const std::string& id, TimeDelta end) {
1647 base::AutoLock auto_lock(lock_); 1352 base::AutoLock auto_lock(lock_);
1648 DVLOG(1) << "SetAppendWindowEnd(" << id << ", " << end.InSecondsF() << ")"; 1353 DVLOG(1) << "SetAppendWindowEnd(" << id << ", " << end.InSecondsF() << ")";
1649 CHECK(IsValidId(id)); 1354 CHECK(IsValidId(id));
1650 source_state_map_[id]->set_append_window_end(end); 1355 source_state_map_[id]->SetAppendWindowEnd(end);
1651 } 1356 }
1652 1357
1653 void ChunkDemuxer::Shutdown() { 1358 void ChunkDemuxer::Shutdown() {
1654 DVLOG(1) << "Shutdown()"; 1359 DVLOG(1) << "Shutdown()";
1655 base::AutoLock auto_lock(lock_); 1360 base::AutoLock auto_lock(lock_);
1656 1361
1657 if (state_ == SHUTDOWN) 1362 if (state_ == SHUTDOWN)
1658 return; 1363 return;
1659 1364
1660 ShutdownAllStreams(); 1365 ShutdownAllStreams();
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after
1880 } 1585 }
1881 1586
1882 void ChunkDemuxer::ShutdownAllStreams() { 1587 void ChunkDemuxer::ShutdownAllStreams() {
1883 for (SourceStateMap::iterator itr = source_state_map_.begin(); 1588 for (SourceStateMap::iterator itr = source_state_map_.begin();
1884 itr != source_state_map_.end(); ++itr) { 1589 itr != source_state_map_.end(); ++itr) {
1885 itr->second->Shutdown(); 1590 itr->second->Shutdown();
1886 } 1591 }
1887 } 1592 }
1888 1593
1889 } // namespace media 1594 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698