| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/filters/chunk_demuxer.h" | 5 #include "media/filters/chunk_demuxer.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <deque> | 8 #include <deque> |
| 9 #include <limits> | 9 #include <limits> |
| 10 | 10 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 41 // Returns true if the data was successfully appended. Returns false if an | 41 // Returns true if the data was successfully appended. Returns false if an |
| 42 // error occurred. | 42 // error occurred. |
| 43 bool Append(const uint8* data, size_t length); | 43 bool Append(const uint8* data, size_t length); |
| 44 | 44 |
| 45 // Aborts the current append sequence and resets the parser. | 45 // Aborts the current append sequence and resets the parser. |
| 46 void Abort(); | 46 void Abort(); |
| 47 | 47 |
| 48 // Sets |timestamp_offset_| if possible. | 48 // Sets |timestamp_offset_| if possible. |
| 49 // Returns if the offset was set. Returns false if the offset could not be | 49 // Returns if the offset was set. Returns false if the offset could not be |
| 50 // updated at this time. | 50 // updated at this time. |
| 51 bool SetTimestampOffset(TimeDelta timestamp_offset); | 51 bool set_timestampOffset(TimeDelta timestamp_offset); |
| 52 | 52 |
| 53 TimeDelta timestamp_offset() const { return timestamp_offset_; } | 53 TimeDelta timestamp_offset() const { return timestamp_offset_; } |
| 54 | 54 |
| 55 private: | 55 private: |
| 56 // Called by the |stream_parser_| at the beginning of a new media segment. | 56 // Called by the |stream_parser_| at the beginning of a new media segment. |
| 57 // |timestamp| is the timestamp on the first buffer in the segment. | 57 // |timestamp| is the timestamp on the first buffer in the segment. |
| 58 // It modifies the state of this object and then calls |new_segment_cb| with | 58 // It modifies the state of this object and then calls |new_segment_cb| with |
| 59 // modified version of |timestamp|. | 59 // modified version of |timestamp|. |
| 60 void OnNewMediaSegment(const StreamParser::NewMediaSegmentCB& new_segment_cb, | 60 void OnNewMediaSegment(const StreamParser::NewMediaSegmentCB& new_segment_cb, |
| 61 TimeDelta timestamp); | 61 TimeDelta timestamp); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 89 // Keeps track of whether |timestamp_offset_| can be modified. | 89 // Keeps track of whether |timestamp_offset_| can be modified. |
| 90 bool can_update_offset_; | 90 bool can_update_offset_; |
| 91 | 91 |
| 92 // The object used to parse appended data. | 92 // The object used to parse appended data. |
| 93 scoped_ptr<StreamParser> stream_parser_; | 93 scoped_ptr<StreamParser> stream_parser_; |
| 94 | 94 |
| 95 DISALLOW_COPY_AND_ASSIGN(SourceState); | 95 DISALLOW_COPY_AND_ASSIGN(SourceState); |
| 96 }; | 96 }; |
| 97 | 97 |
| 98 SourceState::SourceState(scoped_ptr<StreamParser> stream_parser) | 98 SourceState::SourceState(scoped_ptr<StreamParser> stream_parser) |
| 99 : can_update_offset_(true), | 99 : can_update_offset_(true), stream_parser_(stream_parser.release()) {} |
| 100 stream_parser_(stream_parser.release()) { | |
| 101 } | |
| 102 | 100 |
| 103 void SourceState::Init(const StreamParser::InitCB& init_cb, | 101 void SourceState::Init(const StreamParser::InitCB& init_cb, |
| 104 const StreamParser::NewConfigCB& config_cb, | 102 const StreamParser::NewConfigCB& config_cb, |
| 105 const StreamParser::NewBuffersCB& audio_cb, | 103 const StreamParser::NewBuffersCB& audio_cb, |
| 106 const StreamParser::NewBuffersCB& video_cb, | 104 const StreamParser::NewBuffersCB& video_cb, |
| 107 const StreamParser::NewTextBuffersCB& text_cb, | 105 const StreamParser::NewTextBuffersCB& text_cb, |
| 108 const StreamParser::NeedKeyCB& need_key_cb, | 106 const StreamParser::NeedKeyCB& need_key_cb, |
| 109 const AddTextTrackCB& add_text_track_cb, | 107 const AddTextTrackCB& add_text_track_cb, |
| 110 const StreamParser::NewMediaSegmentCB& new_segment_cb, | 108 const StreamParser::NewMediaSegmentCB& new_segment_cb, |
| 111 const LogCB& log_cb) { | 109 const LogCB& log_cb) { |
| 112 stream_parser_->Init(init_cb, config_cb, | 110 stream_parser_->Init( |
| 113 base::Bind(&SourceState::OnBuffers, | 111 init_cb, config_cb, |
| 114 base::Unretained(this), audio_cb), | 112 base::Bind(&SourceState::OnBuffers, base::Unretained(this), audio_cb), |
| 115 base::Bind(&SourceState::OnBuffers, | 113 base::Bind(&SourceState::OnBuffers, base::Unretained(this), video_cb), |
| 116 base::Unretained(this), video_cb), | 114 base::Bind(&SourceState::OnTextBuffers, base::Unretained(this), text_cb), |
| 117 base::Bind(&SourceState::OnTextBuffers, | 115 need_key_cb, add_text_track_cb, |
| 118 base::Unretained(this), text_cb), | 116 base::Bind(&SourceState::OnNewMediaSegment, base::Unretained(this), |
| 119 need_key_cb, | 117 new_segment_cb), |
| 120 add_text_track_cb, | 118 base::Bind(&SourceState::OnEndOfMediaSegment, base::Unretained(this)), |
| 121 base::Bind(&SourceState::OnNewMediaSegment, | 119 log_cb); |
| 122 base::Unretained(this), new_segment_cb), | |
| 123 base::Bind(&SourceState::OnEndOfMediaSegment, | |
| 124 base::Unretained(this)), | |
| 125 log_cb); | |
| 126 } | 120 } |
| 127 | 121 |
| 128 bool SourceState::SetTimestampOffset(TimeDelta timestamp_offset) { | 122 bool SourceState::set_timestampOffset(TimeDelta timestamp_offset) { |
| 129 if (!can_update_offset_) | 123 if (!can_update_offset_) return false; |
| 130 return false; | |
| 131 | 124 |
| 132 timestamp_offset_ = timestamp_offset; | 125 timestamp_offset_ = timestamp_offset; |
| 133 return true; | 126 return true; |
| 134 } | 127 } |
| 135 | 128 |
| 136 bool SourceState::Append(const uint8* data, size_t length) { | 129 bool SourceState::Append(const uint8* data, size_t length) { |
| 137 return stream_parser_->Parse(data, length); | 130 return stream_parser_->Parse(data, length); |
| 138 } | 131 } |
| 139 | 132 |
| 140 void SourceState::Abort() { | 133 void SourceState::Abort() { |
| 141 stream_parser_->Flush(); | 134 stream_parser_->Flush(); |
| 142 can_update_offset_ = true; | 135 can_update_offset_ = true; |
| 143 } | 136 } |
| 144 | 137 |
| 145 void SourceState::AdjustBufferTimestamps( | 138 void SourceState::AdjustBufferTimestamps( |
| 146 const StreamParser::BufferQueue& buffers) { | 139 const StreamParser::BufferQueue& buffers) { |
| 147 if (timestamp_offset_ == TimeDelta()) | 140 if (timestamp_offset_ == TimeDelta()) return; |
| 148 return; | |
| 149 | 141 |
| 150 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); | 142 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); |
| 151 itr != buffers.end(); ++itr) { | 143 itr != buffers.end(); ++itr) { |
| 152 (*itr)->SetDecodeTimestamp( | 144 (*itr) |
| 153 (*itr)->GetDecodeTimestamp() + timestamp_offset_); | 145 ->SetDecodeTimestamp((*itr)->GetDecodeTimestamp() + timestamp_offset_); |
| 154 (*itr)->SetTimestamp((*itr)->GetTimestamp() + timestamp_offset_); | 146 (*itr)->set_timestamp((*itr)->get_timestamp() + timestamp_offset_); |
| 155 } | 147 } |
| 156 } | 148 } |
| 157 | 149 |
| 158 void SourceState::OnNewMediaSegment( | 150 void SourceState::OnNewMediaSegment( |
| 159 const StreamParser::NewMediaSegmentCB& new_segment_cb, | 151 const StreamParser::NewMediaSegmentCB& new_segment_cb, |
| 160 TimeDelta timestamp) { | 152 TimeDelta timestamp) { |
| 161 DCHECK(timestamp != kNoTimestamp()); | 153 DCHECK(timestamp != kNoTimestamp()); |
| 162 DVLOG(2) << "OnNewMediaSegment(" << timestamp.InSecondsF() << ")"; | 154 DVLOG(2) << "OnNewMediaSegment(" << timestamp.InSecondsF() << ")"; |
| 163 | 155 |
| 164 can_update_offset_ = false; | 156 can_update_offset_ = false; |
| 165 new_segment_cb.Run(timestamp + timestamp_offset_); | 157 new_segment_cb.Run(timestamp + timestamp_offset_); |
| 166 } | 158 } |
| 167 | 159 |
| 168 void SourceState::OnEndOfMediaSegment() { | 160 void SourceState::OnEndOfMediaSegment() { |
| 169 DVLOG(2) << "OnEndOfMediaSegment()"; | 161 DVLOG(2) << "OnEndOfMediaSegment()"; |
| 170 can_update_offset_ = true; | 162 can_update_offset_ = true; |
| 171 } | 163 } |
| 172 | 164 |
| 173 bool SourceState::OnBuffers(const StreamParser::NewBuffersCB& new_buffers_cb, | 165 bool SourceState::OnBuffers(const StreamParser::NewBuffersCB& new_buffers_cb, |
| 174 const StreamParser::BufferQueue& buffers) { | 166 const StreamParser::BufferQueue& buffers) { |
| 175 if (new_buffers_cb.is_null()) | 167 if (new_buffers_cb.is_null()) return false; |
| 176 return false; | |
| 177 | 168 |
| 178 AdjustBufferTimestamps(buffers); | 169 AdjustBufferTimestamps(buffers); |
| 179 | 170 |
| 180 return new_buffers_cb.Run(buffers); | 171 return new_buffers_cb.Run(buffers); |
| 181 } | 172 } |
| 182 | 173 |
| 183 bool SourceState::OnTextBuffers( | 174 bool SourceState::OnTextBuffers( |
| 184 const StreamParser::NewTextBuffersCB& new_buffers_cb, | 175 const StreamParser::NewTextBuffersCB& new_buffers_cb, TextTrack* text_track, |
| 185 TextTrack* text_track, | |
| 186 const StreamParser::BufferQueue& buffers) { | 176 const StreamParser::BufferQueue& buffers) { |
| 187 if (new_buffers_cb.is_null()) | 177 if (new_buffers_cb.is_null()) return false; |
| 188 return false; | |
| 189 | 178 |
| 190 AdjustBufferTimestamps(buffers); | 179 AdjustBufferTimestamps(buffers); |
| 191 | 180 |
| 192 return new_buffers_cb.Run(text_track, buffers); | 181 return new_buffers_cb.Run(text_track, buffers); |
| 193 } | 182 } |
| 194 | 183 |
| 195 class ChunkDemuxerStream : public DemuxerStream { | 184 class ChunkDemuxerStream : public DemuxerStream { |
| 196 public: | 185 public: |
| 197 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; | 186 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; |
| 198 typedef std::deque<ReadCB> ReadCBQueue; | 187 typedef std::deque<ReadCB> ReadCBQueue; |
| 199 typedef std::deque<base::Closure> ClosureQueue; | 188 typedef std::deque<base::Closure> ClosureQueue; |
| 200 | 189 |
| 201 ChunkDemuxerStream(const AudioDecoderConfig& audio_config, | 190 ChunkDemuxerStream(const AudioDecoderConfig& audio_config, |
| 202 const LogCB& log_cb); | 191 const LogCB& log_cb); |
| 203 ChunkDemuxerStream(const VideoDecoderConfig& video_config, | 192 ChunkDemuxerStream(const VideoDecoderConfig& video_config, |
| 204 const LogCB& log_cb); | 193 const LogCB& log_cb); |
| 205 virtual ~ChunkDemuxerStream(); | 194 virtual ~ChunkDemuxerStream(); |
| 206 | 195 |
| 207 void StartWaitingForSeek(); | 196 void StartWaitingForSeek(); |
| 208 void Seek(TimeDelta time); | 197 void Seek(TimeDelta time); |
| 209 void CancelPendingSeek(); | 198 void CancelPendingSeek(); |
| 210 bool IsSeekPending() const; | 199 bool IsSeekPending() const; |
| 211 | 200 |
| 212 // Add buffers to this stream. Buffers are stored in SourceBufferStreams, | 201 // Add buffers to this stream. Buffers are stored in SourceBufferStreams, |
| 213 // which handle ordering and overlap resolution. | 202 // which handle ordering and overlap resolution. |
| 214 // Returns true if buffers were successfully added. | 203 // Returns true if buffers were successfully added. |
| 215 bool Append(const StreamParser::BufferQueue& buffers); | 204 bool Append(const StreamParser::BufferQueue& buffers); |
| 216 | 205 |
| 217 // Signal to the stream that duration has changed to |duration|. | 206 // Signal to the stream that duration has changed to |duration|. |
| 218 void OnSetDuration(base::TimeDelta duration); | 207 void Onset_duration(base::TimeDelta duration); |
| 219 | 208 |
| 220 // Returns the range of buffered data in this stream, capped at |duration|. | 209 // Returns the range of buffered data in this stream, capped at |duration|. |
| 221 Ranges<TimeDelta> GetBufferedRanges(base::TimeDelta duration) const; | 210 Ranges<TimeDelta> GetBufferedRanges(base::TimeDelta duration) const; |
| 222 | 211 |
| 223 // Signal to the stream that buffers handed in through subsequent calls to | 212 // Signal to the stream that buffers handed in through subsequent calls to |
| 224 // Append() belong to a media segment that starts at |start_timestamp|. | 213 // Append() belong to a media segment that starts at |start_timestamp|. |
| 225 void OnNewMediaSegment(TimeDelta start_timestamp); | 214 void OnNewMediaSegment(TimeDelta start_timestamp); |
| 226 | 215 |
| 227 // Called when midstream config updates occur. | 216 // Called when midstream config updates occur. |
| 228 // Returns true if the new config is accepted. | 217 // Returns true if the new config is accepted. |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 274 | 263 |
| 275 mutable base::Lock lock_; | 264 mutable base::Lock lock_; |
| 276 State state_; | 265 State state_; |
| 277 ReadCBQueue read_cbs_; | 266 ReadCBQueue read_cbs_; |
| 278 | 267 |
| 279 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream); | 268 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream); |
| 280 }; | 269 }; |
| 281 | 270 |
| 282 ChunkDemuxerStream::ChunkDemuxerStream(const AudioDecoderConfig& audio_config, | 271 ChunkDemuxerStream::ChunkDemuxerStream(const AudioDecoderConfig& audio_config, |
| 283 const LogCB& log_cb) | 272 const LogCB& log_cb) |
| 284 : type_(AUDIO), | 273 : type_(AUDIO), state_(RETURNING_DATA_FOR_READS) { |
| 285 state_(RETURNING_DATA_FOR_READS) { | |
| 286 stream_.reset(new SourceBufferStream(audio_config, log_cb)); | 274 stream_.reset(new SourceBufferStream(audio_config, log_cb)); |
| 287 } | 275 } |
| 288 | 276 |
| 289 ChunkDemuxerStream::ChunkDemuxerStream(const VideoDecoderConfig& video_config, | 277 ChunkDemuxerStream::ChunkDemuxerStream(const VideoDecoderConfig& video_config, |
| 290 const LogCB& log_cb) | 278 const LogCB& log_cb) |
| 291 : type_(VIDEO), | 279 : type_(VIDEO), state_(RETURNING_DATA_FOR_READS) { |
| 292 state_(RETURNING_DATA_FOR_READS) { | |
| 293 stream_.reset(new SourceBufferStream(video_config, log_cb)); | 280 stream_.reset(new SourceBufferStream(video_config, log_cb)); |
| 294 } | 281 } |
| 295 | 282 |
| 296 void ChunkDemuxerStream::StartWaitingForSeek() { | 283 void ChunkDemuxerStream::StartWaitingForSeek() { |
| 297 DVLOG(1) << "ChunkDemuxerStream::StartWaitingForSeek()"; | 284 DVLOG(1) << "ChunkDemuxerStream::StartWaitingForSeek()"; |
| 298 ReadCBQueue read_cbs; | 285 ReadCBQueue read_cbs; |
| 299 { | 286 { |
| 300 base::AutoLock auto_lock(lock_); | 287 base::AutoLock auto_lock(lock_); |
| 301 ChangeState_Locked(WAITING_FOR_SEEK); | 288 ChangeState_Locked(WAITING_FOR_SEEK); |
| 302 std::swap(read_cbs_, read_cbs); | 289 std::swap(read_cbs_, read_cbs); |
| 303 } | 290 } |
| 304 | 291 |
| 305 for (ReadCBQueue::iterator it = read_cbs.begin(); it != read_cbs.end(); ++it) | 292 for (ReadCBQueue::iterator it = read_cbs.begin(); it != read_cbs.end(); ++it) |
| 306 it->Run(kAborted, NULL); | 293 it->Run(kAborted, NULL); |
| 307 } | 294 } |
| 308 | 295 |
| 309 void ChunkDemuxerStream::Seek(TimeDelta time) { | 296 void ChunkDemuxerStream::Seek(TimeDelta time) { |
| 310 base::AutoLock auto_lock(lock_); | 297 base::AutoLock auto_lock(lock_); |
| 311 | 298 |
| 312 DCHECK(read_cbs_.empty()); | 299 DCHECK(read_cbs_.empty()); |
| 313 | 300 |
| 314 // Ignore seek requests when canceled. | 301 // Ignore seek requests when canceled. |
| 315 if (state_ == CANCELED) | 302 if (state_ == CANCELED) return; |
| 316 return; | |
| 317 | 303 |
| 318 stream_->Seek(time); | 304 stream_->Seek(time); |
| 319 | 305 |
| 320 if (state_ == WAITING_FOR_SEEK) | 306 if (state_ == WAITING_FOR_SEEK) ChangeState_Locked(RETURNING_DATA_FOR_READS); |
| 321 ChangeState_Locked(RETURNING_DATA_FOR_READS); | |
| 322 } | 307 } |
| 323 | 308 |
| 324 void ChunkDemuxerStream::CancelPendingSeek() { | 309 void ChunkDemuxerStream::CancelPendingSeek() { |
| 325 DVLOG(1) << "ChunkDemuxerStream::CancelPendingSeek()"; | 310 DVLOG(1) << "ChunkDemuxerStream::CancelPendingSeek()"; |
| 326 ReadCBQueue read_cbs; | 311 ReadCBQueue read_cbs; |
| 327 { | 312 { |
| 328 base::AutoLock auto_lock(lock_); | 313 base::AutoLock auto_lock(lock_); |
| 329 ChangeState_Locked(CANCELED); | 314 ChangeState_Locked(CANCELED); |
| 330 std::swap(read_cbs_, read_cbs); | 315 std::swap(read_cbs_, read_cbs); |
| 331 } | 316 } |
| 332 | 317 |
| 333 for (ReadCBQueue::iterator it = read_cbs.begin(); it != read_cbs.end(); ++it) | 318 for (ReadCBQueue::iterator it = read_cbs.begin(); it != read_cbs.end(); ++it) |
| 334 it->Run(kAborted, NULL); | 319 it->Run(kAborted, NULL); |
| 335 } | 320 } |
| 336 | 321 |
| 337 bool ChunkDemuxerStream::IsSeekPending() const { | 322 bool ChunkDemuxerStream::IsSeekPending() const { |
| 338 base::AutoLock auto_lock(lock_); | 323 base::AutoLock auto_lock(lock_); |
| 339 return stream_->IsSeekPending(); | 324 return stream_->IsSeekPending(); |
| 340 } | 325 } |
| 341 | 326 |
| 342 void ChunkDemuxerStream::OnNewMediaSegment(TimeDelta start_timestamp) { | 327 void ChunkDemuxerStream::OnNewMediaSegment(TimeDelta start_timestamp) { |
| 343 base::AutoLock auto_lock(lock_); | 328 base::AutoLock auto_lock(lock_); |
| 344 stream_->OnNewMediaSegment(start_timestamp); | 329 stream_->OnNewMediaSegment(start_timestamp); |
| 345 } | 330 } |
| 346 | 331 |
| 347 bool ChunkDemuxerStream::Append(const StreamParser::BufferQueue& buffers) { | 332 bool ChunkDemuxerStream::Append(const StreamParser::BufferQueue& buffers) { |
| 348 if (buffers.empty()) | 333 if (buffers.empty()) return false; |
| 349 return false; | |
| 350 | 334 |
| 351 ClosureQueue closures; | 335 ClosureQueue closures; |
| 352 { | 336 { |
| 353 base::AutoLock auto_lock(lock_); | 337 base::AutoLock auto_lock(lock_); |
| 354 DCHECK_NE(state_, SHUTDOWN); | 338 DCHECK_NE(state_, SHUTDOWN); |
| 355 if (!stream_->Append(buffers)) { | 339 if (!stream_->Append(buffers)) { |
| 356 DVLOG(1) << "ChunkDemuxerStream::Append() : stream append failed"; | 340 DVLOG(1) << "ChunkDemuxerStream::Append() : stream append failed"; |
| 357 return false; | 341 return false; |
| 358 } | 342 } |
| 359 CreateReadDoneClosures_Locked(&closures); | 343 CreateReadDoneClosures_Locked(&closures); |
| 360 } | 344 } |
| 361 | 345 |
| 362 for (ClosureQueue::iterator it = closures.begin(); it != closures.end(); ++it) | 346 for (ClosureQueue::iterator it = closures.begin(); it != closures.end(); ++it) |
| 363 it->Run(); | 347 it->Run(); |
| 364 | 348 |
| 365 return true; | 349 return true; |
| 366 } | 350 } |
| 367 | 351 |
| 368 void ChunkDemuxerStream::OnSetDuration(base::TimeDelta duration) { | 352 void ChunkDemuxerStream::Onset_duration(base::TimeDelta duration) { |
| 369 base::AutoLock auto_lock(lock_); | 353 base::AutoLock auto_lock(lock_); |
| 370 stream_->OnSetDuration(duration); | 354 stream_->OnSetDuration(duration); |
| 371 } | 355 } |
| 372 | 356 |
| 373 Ranges<TimeDelta> ChunkDemuxerStream::GetBufferedRanges( | 357 Ranges<TimeDelta> ChunkDemuxerStream::GetBufferedRanges( |
| 374 base::TimeDelta duration) const { | 358 base::TimeDelta duration) const { |
| 375 base::AutoLock auto_lock(lock_); | 359 base::AutoLock auto_lock(lock_); |
| 376 Ranges<TimeDelta> range = stream_->GetBufferedTime(); | 360 Ranges<TimeDelta> range = stream_->GetBufferedTime(); |
| 377 | 361 |
| 378 if (range.size() == 0u) | 362 if (range.size() == 0u) return range; |
| 379 return range; | |
| 380 | 363 |
| 381 // Clamp the end of the stream's buffered ranges to fit within the duration. | 364 // Clamp the end of the stream's buffered ranges to fit within the duration. |
| 382 // This can be done by intersecting the stream's range with the valid time | 365 // This can be done by intersecting the stream's range with the valid time |
| 383 // range. | 366 // range. |
| 384 Ranges<TimeDelta> valid_time_range; | 367 Ranges<TimeDelta> valid_time_range; |
| 385 valid_time_range.Add(range.start(0), duration); | 368 valid_time_range.Add(range.start(0), duration); |
| 386 return range.IntersectionWith(valid_time_range); | 369 return range.IntersectionWith(valid_time_range); |
| 387 } | 370 } |
| 388 | 371 |
| 389 bool ChunkDemuxerStream::UpdateAudioConfig(const AudioDecoderConfig& config) { | 372 bool ChunkDemuxerStream::UpdateAudioConfig(const AudioDecoderConfig& config) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 421 ReadCBQueue read_cbs; | 404 ReadCBQueue read_cbs; |
| 422 { | 405 { |
| 423 base::AutoLock auto_lock(lock_); | 406 base::AutoLock auto_lock(lock_); |
| 424 ChangeState_Locked(SHUTDOWN); | 407 ChangeState_Locked(SHUTDOWN); |
| 425 std::swap(read_cbs_, read_cbs); | 408 std::swap(read_cbs_, read_cbs); |
| 426 } | 409 } |
| 427 | 410 |
| 428 // Pass end of stream buffers to all callbacks to signal that no more data | 411 // Pass end of stream buffers to all callbacks to signal that no more data |
| 429 // will be sent. | 412 // will be sent. |
| 430 for (ReadCBQueue::iterator it = read_cbs.begin(); it != read_cbs.end(); ++it) | 413 for (ReadCBQueue::iterator it = read_cbs.begin(); it != read_cbs.end(); ++it) |
| 431 it->Run(DemuxerStream::kOk, StreamParserBuffer::CreateEOSBuffer()); | 414 it->Run(DemuxerStream::kOk, StreamParserBuffer::create_eos_buffer()); |
| 432 } | 415 } |
| 433 | 416 |
| 434 // Helper function that makes sure |read_cb| runs on |message_loop_proxy|. | 417 // Helper function that makes sure |read_cb| runs on |message_loop_proxy|. |
| 435 static void RunOnMessageLoop( | 418 static void RunOnMessageLoop( |
| 436 const DemuxerStream::ReadCB& read_cb, | 419 const DemuxerStream::ReadCB& read_cb, |
| 437 const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy, | 420 const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy, |
| 438 DemuxerStream::Status status, | 421 DemuxerStream::Status status, const scoped_refptr<DecoderBuffer>& buffer) { |
| 439 const scoped_refptr<DecoderBuffer>& buffer) { | |
| 440 if (!message_loop_proxy->BelongsToCurrentThread()) { | 422 if (!message_loop_proxy->BelongsToCurrentThread()) { |
| 441 message_loop_proxy->PostTask(FROM_HERE, base::Bind( | 423 message_loop_proxy->PostTask( |
| 442 &RunOnMessageLoop, read_cb, message_loop_proxy, status, buffer)); | 424 FROM_HERE, base::Bind(&RunOnMessageLoop, read_cb, message_loop_proxy, |
| 425 status, buffer)); |
| 443 return; | 426 return; |
| 444 } | 427 } |
| 445 | 428 |
| 446 read_cb.Run(status, buffer); | 429 read_cb.Run(status, buffer); |
| 447 } | 430 } |
| 448 | 431 |
| 449 // DemuxerStream methods. | 432 // DemuxerStream methods. |
| 450 void ChunkDemuxerStream::Read(const ReadCB& read_cb) { | 433 void ChunkDemuxerStream::Read(const ReadCB& read_cb) { |
| 451 DemuxerStream::Status status = kOk; | 434 DemuxerStream::Status status = kOk; |
| 452 scoped_refptr<StreamParserBuffer> buffer; | 435 scoped_refptr<StreamParserBuffer> buffer; |
| 453 { | 436 { |
| 454 base::AutoLock auto_lock(lock_); | 437 base::AutoLock auto_lock(lock_); |
| 455 if (!read_cbs_.empty() || !GetNextBuffer_Locked(&status, &buffer)) { | 438 if (!read_cbs_.empty() || !GetNextBuffer_Locked(&status, &buffer)) { |
| 456 DeferRead_Locked(read_cb); | 439 DeferRead_Locked(read_cb); |
| 457 return; | 440 return; |
| 458 } | 441 } |
| 459 } | 442 } |
| 460 | 443 |
| 461 base::MessageLoopProxy::current()->PostTask(FROM_HERE, base::Bind( | 444 base::MessageLoopProxy::current()->PostTask( |
| 462 read_cb, status, buffer)); | 445 FROM_HERE, base::Bind(read_cb, status, buffer)); |
| 463 } | 446 } |
| 464 | 447 |
| 465 DemuxerStream::Type ChunkDemuxerStream::type() { return type_; } | 448 DemuxerStream::Type ChunkDemuxerStream::type() { return type_; } |
| 466 | 449 |
| 467 void ChunkDemuxerStream::EnableBitstreamConverter() {} | 450 void ChunkDemuxerStream::EnableBitstreamConverter() {} |
| 468 | 451 |
| 469 AudioDecoderConfig ChunkDemuxerStream::audio_decoder_config() { | 452 AudioDecoderConfig ChunkDemuxerStream::audio_decoder_config() { |
| 470 CHECK_EQ(type_, AUDIO); | 453 CHECK_EQ(type_, AUDIO); |
| 471 base::AutoLock auto_lock(lock_); | 454 base::AutoLock auto_lock(lock_); |
| 472 return stream_->GetCurrentAudioDecoderConfig(); | 455 return stream_->GetCurrentAudioDecoderConfig(); |
| 473 } | 456 } |
| 474 | 457 |
| 475 VideoDecoderConfig ChunkDemuxerStream::video_decoder_config() { | 458 VideoDecoderConfig ChunkDemuxerStream::video_decoder_config() { |
| 476 CHECK_EQ(type_, VIDEO); | 459 CHECK_EQ(type_, VIDEO); |
| 477 base::AutoLock auto_lock(lock_); | 460 base::AutoLock auto_lock(lock_); |
| 478 return stream_->GetCurrentVideoDecoderConfig(); | 461 return stream_->GetCurrentVideoDecoderConfig(); |
| 479 } | 462 } |
| 480 | 463 |
| 481 void ChunkDemuxerStream::ChangeState_Locked(State state) { | 464 void ChunkDemuxerStream::ChangeState_Locked(State state) { |
| 482 lock_.AssertAcquired(); | 465 lock_.AssertAcquired(); |
| 483 DVLOG(1) << "ChunkDemuxerStream::ChangeState_Locked() : " | 466 DVLOG(1) << "ChunkDemuxerStream::ChangeState_Locked() : " |
| 484 << "type " << type_ | 467 << "type " << type_ << " - " << state_ << " -> " << state; |
| 485 << " - " << state_ << " -> " << state; | |
| 486 state_ = state; | 468 state_ = state; |
| 487 } | 469 } |
| 488 | 470 |
| 489 ChunkDemuxerStream::~ChunkDemuxerStream() {} | 471 ChunkDemuxerStream::~ChunkDemuxerStream() {} |
| 490 | 472 |
| 491 void ChunkDemuxerStream::DeferRead_Locked(const ReadCB& read_cb) { | 473 void ChunkDemuxerStream::DeferRead_Locked(const ReadCB& read_cb) { |
| 492 lock_.AssertAcquired(); | 474 lock_.AssertAcquired(); |
| 493 // Wrap & store |read_cb| so that it will | 475 // Wrap & store |read_cb| so that it will |
| 494 // get called on the current MessageLoop. | 476 // get called on the current MessageLoop. |
| 495 read_cbs_.push_back(base::Bind(&RunOnMessageLoop, read_cb, | 477 read_cbs_.push_back(base::Bind(&RunOnMessageLoop, read_cb, |
| 496 base::MessageLoopProxy::current())); | 478 base::MessageLoopProxy::current())); |
| 497 } | 479 } |
| 498 | 480 |
| 499 void ChunkDemuxerStream::CreateReadDoneClosures_Locked(ClosureQueue* closures) { | 481 void ChunkDemuxerStream::CreateReadDoneClosures_Locked(ClosureQueue* closures) { |
| 500 lock_.AssertAcquired(); | 482 lock_.AssertAcquired(); |
| 501 | 483 |
| 502 if (state_ != RETURNING_DATA_FOR_READS) | 484 if (state_ != RETURNING_DATA_FOR_READS) return; |
| 503 return; | |
| 504 | 485 |
| 505 DemuxerStream::Status status; | 486 DemuxerStream::Status status; |
| 506 scoped_refptr<StreamParserBuffer> buffer; | 487 scoped_refptr<StreamParserBuffer> buffer; |
| 507 while (!read_cbs_.empty()) { | 488 while (!read_cbs_.empty()) { |
| 508 if (!GetNextBuffer_Locked(&status, &buffer)) | 489 if (!GetNextBuffer_Locked(&status, &buffer)) return; |
| 509 return; | 490 closures->push_back(base::Bind(read_cbs_.front(), status, buffer)); |
| 510 closures->push_back(base::Bind(read_cbs_.front(), | |
| 511 status, buffer)); | |
| 512 read_cbs_.pop_front(); | 491 read_cbs_.pop_front(); |
| 513 } | 492 } |
| 514 } | 493 } |
| 515 | 494 |
| 516 bool ChunkDemuxerStream::GetNextBuffer_Locked( | 495 bool ChunkDemuxerStream::GetNextBuffer_Locked( |
| 517 DemuxerStream::Status* status, | 496 DemuxerStream::Status* status, scoped_refptr<StreamParserBuffer>* buffer) { |
| 518 scoped_refptr<StreamParserBuffer>* buffer) { | |
| 519 lock_.AssertAcquired(); | 497 lock_.AssertAcquired(); |
| 520 | 498 |
| 521 switch (state_) { | 499 switch (state_) { |
| 522 case RETURNING_DATA_FOR_READS: | 500 case RETURNING_DATA_FOR_READS: |
| 523 switch (stream_->GetNextBuffer(buffer)) { | 501 switch (stream_->GetNextBuffer(buffer)) { |
| 524 case SourceBufferStream::kSuccess: | 502 case SourceBufferStream::kSuccess: |
| 525 *status = DemuxerStream::kOk; | 503 *status = DemuxerStream::kOk; |
| 526 return true; | 504 return true; |
| 527 case SourceBufferStream::kNeedBuffer: | 505 case SourceBufferStream::kNeedBuffer: |
| 528 return false; | 506 return false; |
| 529 case SourceBufferStream::kEndOfStream: | 507 case SourceBufferStream::kEndOfStream: |
| 530 *status = DemuxerStream::kOk; | 508 *status = DemuxerStream::kOk; |
| 531 *buffer = StreamParserBuffer::CreateEOSBuffer(); | 509 *buffer = StreamParserBuffer::create_eos_buffer(); |
| 532 return true; | 510 return true; |
| 533 case SourceBufferStream::kConfigChange: | 511 case SourceBufferStream::kConfigChange: |
| 534 DVLOG(2) << "Config change reported to ChunkDemuxerStream."; | 512 DVLOG(2) << "Config change reported to ChunkDemuxerStream."; |
| 535 *status = kConfigChanged; | 513 *status = kConfigChanged; |
| 536 *buffer = NULL; | 514 *buffer = NULL; |
| 537 return true; | 515 return true; |
| 538 } | 516 } |
| 539 break; | 517 break; |
| 540 case CANCELED: | 518 case CANCELED: |
| 541 case WAITING_FOR_SEEK: | 519 case WAITING_FOR_SEEK: |
| 542 // Null buffers should be returned in this state since we are waiting | 520 // Null buffers should be returned in this state since we are waiting |
| 543 // for a seek. Any buffers in the SourceBuffer should NOT be returned | 521 // for a seek. Any buffers in the SourceBuffer should NOT be returned |
| 544 // because they are associated with the seek. | 522 // because they are associated with the seek. |
| 545 DCHECK(read_cbs_.empty()); | 523 DCHECK(read_cbs_.empty()); |
| 546 *status = DemuxerStream::kAborted; | 524 *status = DemuxerStream::kAborted; |
| 547 *buffer = NULL; | 525 *buffer = NULL; |
| 548 return true; | 526 return true; |
| 549 case SHUTDOWN: | 527 case SHUTDOWN: |
| 550 DCHECK(read_cbs_.empty()); | 528 DCHECK(read_cbs_.empty()); |
| 551 *status = DemuxerStream::kOk; | 529 *status = DemuxerStream::kOk; |
| 552 *buffer = StreamParserBuffer::CreateEOSBuffer(); | 530 *buffer = StreamParserBuffer::create_eos_buffer(); |
| 553 return true; | 531 return true; |
| 554 } | 532 } |
| 555 | 533 |
| 556 NOTREACHED(); | 534 NOTREACHED(); |
| 557 return false; | 535 return false; |
| 558 } | 536 } |
| 559 | 537 |
| 560 ChunkDemuxer::ChunkDemuxer(const base::Closure& open_cb, | 538 ChunkDemuxer::ChunkDemuxer(const base::Closure& open_cb, |
| 561 const NeedKeyCB& need_key_cb, | 539 const NeedKeyCB& need_key_cb, |
| 562 const AddTextTrackCB& add_text_track_cb, | 540 const AddTextTrackCB& add_text_track_cb, |
| 563 const LogCB& log_cb) | 541 const LogCB& log_cb) |
| 564 : state_(WAITING_FOR_INIT), | 542 : state_(WAITING_FOR_INIT), |
| 565 host_(NULL), | 543 host_(NULL), |
| 566 open_cb_(open_cb), | 544 open_cb_(open_cb), |
| 567 need_key_cb_(need_key_cb), | 545 need_key_cb_(need_key_cb), |
| 568 add_text_track_cb_(add_text_track_cb), | 546 add_text_track_cb_(add_text_track_cb), |
| 569 log_cb_(log_cb), | 547 log_cb_(log_cb), |
| 570 duration_(kNoTimestamp()), | 548 duration_(kNoTimestamp()), |
| 571 user_specified_duration_(-1) { | 549 user_specified_duration_(-1) { |
| 572 DCHECK(!open_cb_.is_null()); | 550 DCHECK(!open_cb_.is_null()); |
| 573 DCHECK(!need_key_cb_.is_null()); | 551 DCHECK(!need_key_cb_.is_null()); |
| 574 } | 552 } |
| 575 | 553 |
| 576 void ChunkDemuxer::Initialize(DemuxerHost* host, const PipelineStatusCB& cb) { | 554 void ChunkDemuxer::Initialize(DemuxerHost* host, const PipelineStatusCB& cb) { |
| 577 DVLOG(1) << "Init()"; | 555 DVLOG(1) << "Init()"; |
| 578 | 556 |
| 579 base::AutoLock auto_lock(lock_); | 557 base::AutoLock auto_lock(lock_); |
| 580 | 558 |
| 581 if (state_ == SHUTDOWN) { | 559 if (state_ == SHUTDOWN) { |
| 582 base::MessageLoopProxy::current()->PostTask(FROM_HERE, base::Bind( | 560 base::MessageLoopProxy::current()->PostTask( |
| 583 cb, DEMUXER_ERROR_COULD_NOT_OPEN)); | 561 FROM_HERE, base::Bind(cb, DEMUXER_ERROR_COULD_NOT_OPEN)); |
| 584 return; | 562 return; |
| 585 } | 563 } |
| 586 DCHECK_EQ(state_, WAITING_FOR_INIT); | 564 DCHECK_EQ(state_, WAITING_FOR_INIT); |
| 587 host_ = host; | 565 host_ = host; |
| 588 | 566 |
| 589 ChangeState_Locked(INITIALIZING); | 567 ChangeState_Locked(INITIALIZING); |
| 590 init_cb_ = cb; | 568 init_cb_ = cb; |
| 591 | 569 |
| 592 base::ResetAndReturn(&open_cb_).Run(); | 570 base::ResetAndReturn(&open_cb_).Run(); |
| 593 } | 571 } |
| 594 | 572 |
| 595 void ChunkDemuxer::Stop(const base::Closure& callback) { | 573 void ChunkDemuxer::Stop(const base::Closure& callback) { |
| 596 DVLOG(1) << "Stop()"; | 574 DVLOG(1) << "Stop()"; |
| 597 Shutdown(); | 575 Shutdown(); |
| 598 callback.Run(); | 576 callback.Run(); |
| 599 } | 577 } |
| 600 | 578 |
| 601 void ChunkDemuxer::Seek(TimeDelta time, const PipelineStatusCB& cb) { | 579 void ChunkDemuxer::Seek(TimeDelta time, const PipelineStatusCB& cb) { |
| 602 DVLOG(1) << "Seek(" << time.InSecondsF() << ")"; | 580 DVLOG(1) << "Seek(" << time.InSecondsF() << ")"; |
| 603 DCHECK(time >= TimeDelta()); | 581 DCHECK(time >= TimeDelta()); |
| 604 DCHECK(seek_cb_.is_null()); | 582 DCHECK(seek_cb_.is_null()); |
| 605 | 583 |
| 606 PipelineStatus status = PIPELINE_ERROR_INVALID_STATE; | 584 PipelineStatus status = PIPELINE_ERROR_INVALID_STATE; |
| 607 { | 585 { |
| 608 base::AutoLock auto_lock(lock_); | 586 base::AutoLock auto_lock(lock_); |
| 609 | 587 |
| 610 if (state_ == INITIALIZED || state_ == ENDED) { | 588 if (state_ == INITIALIZED || state_ == ENDED) { |
| 611 if (audio_) | 589 if (audio_) audio_->Seek(time); |
| 612 audio_->Seek(time); | |
| 613 | 590 |
| 614 if (video_) | 591 if (video_) video_->Seek(time); |
| 615 video_->Seek(time); | |
| 616 | 592 |
| 617 if (IsSeekPending_Locked()) { | 593 if (IsSeekPending_Locked()) { |
| 618 DVLOG(1) << "Seek() : waiting for more data to arrive."; | 594 DVLOG(1) << "Seek() : waiting for more data to arrive."; |
| 619 seek_cb_ = cb; | 595 seek_cb_ = cb; |
| 620 return; | 596 return; |
| 621 } | 597 } |
| 622 | 598 |
| 623 status = PIPELINE_OK; | 599 status = PIPELINE_OK; |
| 624 } | 600 } |
| 625 } | 601 } |
| 626 | 602 |
| 627 cb.Run(status); | 603 cb.Run(status); |
| 628 } | 604 } |
| 629 | 605 |
| 630 void ChunkDemuxer::OnAudioRendererDisabled() { | 606 void ChunkDemuxer::OnAudioRendererDisabled() { |
| 631 base::AutoLock auto_lock(lock_); | 607 base::AutoLock auto_lock(lock_); |
| 632 audio_->Shutdown(); | 608 audio_->Shutdown(); |
| 633 disabled_audio_ = audio_.Pass(); | 609 disabled_audio_ = audio_.Pass(); |
| 634 } | 610 } |
| 635 | 611 |
| 636 // Demuxer implementation. | 612 // Demuxer implementation. |
| 637 DemuxerStream* ChunkDemuxer::GetStream(DemuxerStream::Type type) { | 613 DemuxerStream* ChunkDemuxer::GetStream(DemuxerStream::Type type) { |
| 638 base::AutoLock auto_lock(lock_); | 614 base::AutoLock auto_lock(lock_); |
| 639 if (type == DemuxerStream::VIDEO) | 615 if (type == DemuxerStream::VIDEO) return video_.get(); |
| 640 return video_.get(); | |
| 641 | 616 |
| 642 if (type == DemuxerStream::AUDIO) | 617 if (type == DemuxerStream::AUDIO) return audio_.get(); |
| 643 return audio_.get(); | |
| 644 | 618 |
| 645 return NULL; | 619 return NULL; |
| 646 } | 620 } |
| 647 | 621 |
| 648 TimeDelta ChunkDemuxer::GetStartTime() const { | 622 TimeDelta ChunkDemuxer::GetStartTime() const { return TimeDelta(); } |
| 649 return TimeDelta(); | |
| 650 } | |
| 651 | 623 |
| 652 void ChunkDemuxer::StartWaitingForSeek() { | 624 void ChunkDemuxer::StartWaitingForSeek() { |
| 653 DVLOG(1) << "StartWaitingForSeek()"; | 625 DVLOG(1) << "StartWaitingForSeek()"; |
| 654 base::AutoLock auto_lock(lock_); | 626 base::AutoLock auto_lock(lock_); |
| 655 DCHECK(state_ == INITIALIZED || state_ == ENDED || state_ == SHUTDOWN); | 627 DCHECK(state_ == INITIALIZED || state_ == ENDED || state_ == SHUTDOWN); |
| 656 | 628 |
| 657 if (state_ == SHUTDOWN) | 629 if (state_ == SHUTDOWN) return; |
| 658 return; | |
| 659 | 630 |
| 660 if (audio_) | 631 if (audio_) audio_->StartWaitingForSeek(); |
| 661 audio_->StartWaitingForSeek(); | |
| 662 | 632 |
| 663 if (video_) | 633 if (video_) video_->StartWaitingForSeek(); |
| 664 video_->StartWaitingForSeek(); | |
| 665 } | 634 } |
| 666 | 635 |
| 667 void ChunkDemuxer::CancelPendingSeek() { | 636 void ChunkDemuxer::CancelPendingSeek() { |
| 668 PipelineStatusCB cb; | 637 PipelineStatusCB cb; |
| 669 { | 638 { |
| 670 base::AutoLock auto_lock(lock_); | 639 base::AutoLock auto_lock(lock_); |
| 671 if (IsSeekPending_Locked() && !seek_cb_.is_null()) { | 640 if (IsSeekPending_Locked() && !seek_cb_.is_null()) { |
| 672 std::swap(cb, seek_cb_); | 641 std::swap(cb, seek_cb_); |
| 673 } | 642 } |
| 674 if (audio_) | 643 if (audio_) audio_->CancelPendingSeek(); |
| 675 audio_->CancelPendingSeek(); | |
| 676 | 644 |
| 677 if (video_) | 645 if (video_) video_->CancelPendingSeek(); |
| 678 video_->CancelPendingSeek(); | |
| 679 } | 646 } |
| 680 | 647 |
| 681 if (!cb.is_null()) | 648 if (!cb.is_null()) cb.Run(PIPELINE_OK); |
| 682 cb.Run(PIPELINE_OK); | |
| 683 } | 649 } |
| 684 | 650 |
| 685 ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id, | 651 ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id, |
| 686 const std::string& type, | 652 const std::string& type, |
| 687 std::vector<std::string>& codecs) { | 653 std::vector<std::string>& codecs) { |
| 688 DCHECK_GT(codecs.size(), 0u); | 654 DCHECK_GT(codecs.size(), 0u); |
| 689 base::AutoLock auto_lock(lock_); | 655 base::AutoLock auto_lock(lock_); |
| 690 | 656 |
| 691 if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || IsValidId(id)) | 657 if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || IsValidId(id)) |
| 692 return kReachedIdLimit; | 658 return kReachedIdLimit; |
| 693 | 659 |
| 694 bool has_audio = false; | 660 bool has_audio = false; |
| 695 bool has_video = false; | 661 bool has_video = false; |
| 696 scoped_ptr<media::StreamParser> stream_parser( | 662 scoped_ptr<media::StreamParser> stream_parser(StreamParserFactory::Create( |
| 697 StreamParserFactory::Create(type, codecs, log_cb_, | 663 type, codecs, log_cb_, &has_audio, &has_video)); |
| 698 &has_audio, &has_video)); | |
| 699 | 664 |
| 700 if (!stream_parser) | 665 if (!stream_parser) return ChunkDemuxer::kNotSupported; |
| 701 return ChunkDemuxer::kNotSupported; | |
| 702 | 666 |
| 703 if ((has_audio && !source_id_audio_.empty()) || | 667 if ((has_audio && !source_id_audio_.empty()) || |
| 704 (has_video && !source_id_video_.empty())) | 668 (has_video && !source_id_video_.empty())) |
| 705 return kReachedIdLimit; | 669 return kReachedIdLimit; |
| 706 | 670 |
| 707 StreamParser::NewBuffersCB audio_cb; | 671 StreamParser::NewBuffersCB audio_cb; |
| 708 StreamParser::NewBuffersCB video_cb; | 672 StreamParser::NewBuffersCB video_cb; |
| 709 | 673 |
| 710 if (has_audio) { | 674 if (has_audio) { |
| 711 source_id_audio_ = id; | 675 source_id_audio_ = id; |
| 712 audio_cb = base::Bind(&ChunkDemuxer::OnAudioBuffers, | 676 audio_cb = |
| 713 base::Unretained(this)); | 677 base::Bind(&ChunkDemuxer::OnAudioBuffers, base::Unretained(this)); |
| 714 } | 678 } |
| 715 | 679 |
| 716 if (has_video) { | 680 if (has_video) { |
| 717 source_id_video_ = id; | 681 source_id_video_ = id; |
| 718 video_cb = base::Bind(&ChunkDemuxer::OnVideoBuffers, | 682 video_cb = |
| 719 base::Unretained(this)); | 683 base::Bind(&ChunkDemuxer::OnVideoBuffers, base::Unretained(this)); |
| 720 } | 684 } |
| 721 | 685 |
| 722 scoped_ptr<SourceState> source_state(new SourceState(stream_parser.Pass())); | 686 scoped_ptr<SourceState> source_state(new SourceState(stream_parser.Pass())); |
| 723 source_state->Init( | 687 source_state->Init( |
| 724 base::Bind(&ChunkDemuxer::OnSourceInitDone, base::Unretained(this)), | 688 base::Bind(&ChunkDemuxer::OnSourceInitDone, base::Unretained(this)), |
| 725 base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this), | 689 base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this), has_audio, |
| 726 has_audio, has_video), | 690 has_video), |
| 727 audio_cb, | 691 audio_cb, video_cb, |
| 728 video_cb, | |
| 729 base::Bind(&ChunkDemuxer::OnTextBuffers, base::Unretained(this)), | 692 base::Bind(&ChunkDemuxer::OnTextBuffers, base::Unretained(this)), |
| 730 base::Bind(&ChunkDemuxer::OnNeedKey, base::Unretained(this)), | 693 base::Bind(&ChunkDemuxer::OnNeedKey, base::Unretained(this)), |
| 731 add_text_track_cb_, | 694 add_text_track_cb_, |
| 732 base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id), | 695 base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id), |
| 733 log_cb_); | 696 log_cb_); |
| 734 | 697 |
| 735 source_state_map_[id] = source_state.release(); | 698 source_state_map_[id] = source_state.release(); |
| 736 return kOk; | 699 return kOk; |
| 737 } | 700 } |
| 738 | 701 |
| 739 void ChunkDemuxer::RemoveId(const std::string& id) { | 702 void ChunkDemuxer::RemoveId(const std::string& id) { |
| 740 base::AutoLock auto_lock(lock_); | 703 base::AutoLock auto_lock(lock_); |
| 741 CHECK(IsValidId(id)); | 704 CHECK(IsValidId(id)); |
| 742 | 705 |
| 743 delete source_state_map_[id]; | 706 delete source_state_map_[id]; |
| 744 source_state_map_.erase(id); | 707 source_state_map_.erase(id); |
| 745 | 708 |
| 746 if (source_id_audio_ == id) { | 709 if (source_id_audio_ == id) { |
| 747 if (audio_) | 710 if (audio_) audio_->Shutdown(); |
| 748 audio_->Shutdown(); | |
| 749 source_id_audio_.clear(); | 711 source_id_audio_.clear(); |
| 750 } | 712 } |
| 751 | 713 |
| 752 if (source_id_video_ == id) { | 714 if (source_id_video_ == id) { |
| 753 if (video_) | 715 if (video_) video_->Shutdown(); |
| 754 video_->Shutdown(); | |
| 755 source_id_video_.clear(); | 716 source_id_video_.clear(); |
| 756 } | 717 } |
| 757 } | 718 } |
| 758 | 719 |
| 759 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const { | 720 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const { |
| 760 base::AutoLock auto_lock(lock_); | 721 base::AutoLock auto_lock(lock_); |
| 761 DCHECK(!id.empty()); | 722 DCHECK(!id.empty()); |
| 762 DCHECK(IsValidId(id)); | 723 DCHECK(IsValidId(id)); |
| 763 DCHECK(id == source_id_audio_ || id == source_id_video_); | 724 DCHECK(id == source_id_audio_ || id == source_id_video_); |
| 764 | 725 |
| 765 if (id == source_id_audio_ && id != source_id_video_) { | 726 if (id == source_id_audio_ && id != source_id_video_) { |
| 766 // Only include ranges that have been buffered in |audio_| | 727 // Only include ranges that have been buffered in |audio_| |
| 767 return audio_ ? audio_->GetBufferedRanges(duration_) : Ranges<TimeDelta>(); | 728 return audio_ ? audio_->GetBufferedRanges(duration_) : Ranges<TimeDelta>(); |
| 768 } | 729 } |
| 769 | 730 |
| 770 if (id != source_id_audio_ && id == source_id_video_) { | 731 if (id != source_id_audio_ && id == source_id_video_) { |
| 771 // Only include ranges that have been buffered in |video_| | 732 // Only include ranges that have been buffered in |video_| |
| 772 return video_ ? video_->GetBufferedRanges(duration_) : Ranges<TimeDelta>(); | 733 return video_ ? video_->GetBufferedRanges(duration_) : Ranges<TimeDelta>(); |
| 773 } | 734 } |
| 774 | 735 |
| 775 return ComputeIntersection(); | 736 return ComputeIntersection(); |
| 776 } | 737 } |
| 777 | 738 |
| 778 Ranges<TimeDelta> ChunkDemuxer::ComputeIntersection() const { | 739 Ranges<TimeDelta> ChunkDemuxer::ComputeIntersection() const { |
| 779 lock_.AssertAcquired(); | 740 lock_.AssertAcquired(); |
| 780 | 741 |
| 781 if (!audio_ || !video_) | 742 if (!audio_ || !video_) return Ranges<TimeDelta>(); |
| 782 return Ranges<TimeDelta>(); | |
| 783 | 743 |
| 784 // Include ranges that have been buffered in both |audio_| and |video_|. | 744 // Include ranges that have been buffered in both |audio_| and |video_|. |
| 785 Ranges<TimeDelta> audio_ranges = audio_->GetBufferedRanges(duration_); | 745 Ranges<TimeDelta> audio_ranges = audio_->GetBufferedRanges(duration_); |
| 786 Ranges<TimeDelta> video_ranges = video_->GetBufferedRanges(duration_); | 746 Ranges<TimeDelta> video_ranges = video_->GetBufferedRanges(duration_); |
| 787 Ranges<TimeDelta> result = audio_ranges.IntersectionWith(video_ranges); | 747 Ranges<TimeDelta> result = audio_ranges.IntersectionWith(video_ranges); |
| 788 | 748 |
| 789 if (state_ == ENDED && result.size() > 0) { | 749 if (state_ == ENDED && result.size() > 0) { |
| 790 // If appending has ended, extend the last intersection range to include the | 750 // If appending has ended, extend the last intersection range to include the |
| 791 // max end time of the last audio/video range. This allows the buffered | 751 // max end time of the last audio/video range. This allows the buffered |
| 792 // information to match the actual time range that will get played out if | 752 // information to match the actual time range that will get played out if |
| 793 // the streams have slightly different lengths. | 753 // the streams have slightly different lengths. |
| 794 TimeDelta audio_start = audio_ranges.start(audio_ranges.size() - 1); | 754 TimeDelta audio_start = audio_ranges.start(audio_ranges.size() - 1); |
| 795 TimeDelta audio_end = audio_ranges.end(audio_ranges.size() - 1); | 755 TimeDelta audio_end = audio_ranges.end(audio_ranges.size() - 1); |
| 796 TimeDelta video_start = video_ranges.start(video_ranges.size() - 1); | 756 TimeDelta video_start = video_ranges.start(video_ranges.size() - 1); |
| 797 TimeDelta video_end = video_ranges.end(video_ranges.size() - 1); | 757 TimeDelta video_end = video_ranges.end(video_ranges.size() - 1); |
| 798 | 758 |
| 799 // Verify the last audio range overlaps with the last video range. | 759 // Verify the last audio range overlaps with the last video range. |
| 800 // This is enforced by the logic that controls the transition to ENDED. | 760 // This is enforced by the logic that controls the transition to ENDED. |
| 801 DCHECK((audio_start <= video_start && video_start <= audio_end) || | 761 DCHECK((audio_start <= video_start && video_start <= audio_end) || |
| 802 (video_start <= audio_start && audio_start <= video_end)); | 762 (video_start <= audio_start && audio_start <= video_end)); |
| 803 result.Add(result.end(result.size()-1), std::max(audio_end, video_end)); | 763 result.Add(result.end(result.size() - 1), std::max(audio_end, video_end)); |
| 804 } | 764 } |
| 805 | 765 |
| 806 return result; | 766 return result; |
| 807 } | 767 } |
| 808 | 768 |
| 809 void ChunkDemuxer::AppendData(const std::string& id, | 769 void ChunkDemuxer::AppendData(const std::string& id, const uint8* data, |
| 810 const uint8* data, | |
| 811 size_t length) { | 770 size_t length) { |
| 812 DVLOG(1) << "AppendData(" << id << ", " << length << ")"; | 771 DVLOG(1) << "AppendData(" << id << ", " << length << ")"; |
| 813 | 772 |
| 814 DCHECK(!id.empty()); | 773 DCHECK(!id.empty()); |
| 815 | 774 |
| 816 Ranges<TimeDelta> ranges; | 775 Ranges<TimeDelta> ranges; |
| 817 | 776 |
| 818 PipelineStatusCB cb; | 777 PipelineStatusCB cb; |
| 819 { | 778 { |
| 820 base::AutoLock auto_lock(lock_); | 779 base::AutoLock auto_lock(lock_); |
| 821 | 780 |
| 822 // Capture if the SourceBuffer has a pending seek before we start parsing. | 781 // Capture if the SourceBuffer has a pending seek before we start parsing. |
| 823 bool old_seek_pending = IsSeekPending_Locked(); | 782 bool old_seek_pending = IsSeekPending_Locked(); |
| 824 | 783 |
| 825 if (state_ == ENDED) { | 784 if (state_ == ENDED) { |
| 826 ChangeState_Locked(INITIALIZED); | 785 ChangeState_Locked(INITIALIZED); |
| 827 | 786 |
| 828 if (audio_) | 787 if (audio_) audio_->CancelEndOfStream(); |
| 829 audio_->CancelEndOfStream(); | |
| 830 | 788 |
| 831 if (video_) | 789 if (video_) video_->CancelEndOfStream(); |
| 832 video_->CancelEndOfStream(); | |
| 833 } | 790 } |
| 834 | 791 |
| 835 if (length == 0u) | 792 if (length == 0u) return; |
| 836 return; | |
| 837 | 793 |
| 838 DCHECK(data); | 794 DCHECK(data); |
| 839 | 795 |
| 840 switch (state_) { | 796 switch (state_) { |
| 841 case INITIALIZING: | 797 case INITIALIZING: |
| 842 DCHECK(IsValidId(id)); | 798 DCHECK(IsValidId(id)); |
| 843 if (!source_state_map_[id]->Append(data, length)) { | 799 if (!source_state_map_[id]->Append(data, length)) { |
| 844 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); | 800 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); |
| 845 return; | 801 return; |
| 846 } | 802 } |
| (...skipping 23 matching lines...) Expand all Loading... |
| 870 if (old_seek_pending && !IsSeekPending_Locked() && !seek_cb_.is_null()) { | 826 if (old_seek_pending && !IsSeekPending_Locked() && !seek_cb_.is_null()) { |
| 871 std::swap(cb, seek_cb_); | 827 std::swap(cb, seek_cb_); |
| 872 } | 828 } |
| 873 | 829 |
| 874 ranges = GetBufferedRanges(); | 830 ranges = GetBufferedRanges(); |
| 875 } | 831 } |
| 876 | 832 |
| 877 for (size_t i = 0; i < ranges.size(); ++i) | 833 for (size_t i = 0; i < ranges.size(); ++i) |
| 878 host_->AddBufferedTimeRange(ranges.start(i), ranges.end(i)); | 834 host_->AddBufferedTimeRange(ranges.start(i), ranges.end(i)); |
| 879 | 835 |
| 880 if (!cb.is_null()) | 836 if (!cb.is_null()) cb.Run(PIPELINE_OK); |
| 881 cb.Run(PIPELINE_OK); | |
| 882 } | 837 } |
| 883 | 838 |
| 884 void ChunkDemuxer::Abort(const std::string& id) { | 839 void ChunkDemuxer::Abort(const std::string& id) { |
| 885 DVLOG(1) << "Abort(" << id << ")"; | 840 DVLOG(1) << "Abort(" << id << ")"; |
| 886 base::AutoLock auto_lock(lock_); | 841 base::AutoLock auto_lock(lock_); |
| 887 DCHECK(!id.empty()); | 842 DCHECK(!id.empty()); |
| 888 CHECK(IsValidId(id)); | 843 CHECK(IsValidId(id)); |
| 889 source_state_map_[id]->Abort(); | 844 source_state_map_[id]->Abort(); |
| 890 } | 845 } |
| 891 | 846 |
| 892 double ChunkDemuxer::GetDuration() { | 847 double ChunkDemuxer::GetDuration() { |
| 893 base::AutoLock auto_lock(lock_); | 848 base::AutoLock auto_lock(lock_); |
| 894 return GetDuration_Locked(); | 849 return GetDuration_Locked(); |
| 895 } | 850 } |
| 896 | 851 |
| 897 double ChunkDemuxer::GetDuration_Locked() { | 852 double ChunkDemuxer::GetDuration_Locked() { |
| 898 lock_.AssertAcquired(); | 853 lock_.AssertAcquired(); |
| 899 if (duration_ == kNoTimestamp()) | 854 if (duration_ == kNoTimestamp()) |
| 900 return std::numeric_limits<double>::quiet_NaN(); | 855 return std::numeric_limits<double>::quiet_NaN(); |
| 901 | 856 |
| 902 // Return positive infinity if the resource is unbounded. | 857 // Return positive infinity if the resource is unbounded. |
| 903 // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#dom-
media-duration | 858 // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#dom-
media-duration |
| 904 if (duration_ == kInfiniteDuration()) | 859 if (duration_ == kInfiniteDuration()) |
| 905 return std::numeric_limits<double>::infinity(); | 860 return std::numeric_limits<double>::infinity(); |
| 906 | 861 |
| 907 if (user_specified_duration_ >= 0) | 862 if (user_specified_duration_ >= 0) return user_specified_duration_; |
| 908 return user_specified_duration_; | |
| 909 | 863 |
| 910 return duration_.InSecondsF(); | 864 return duration_.InSecondsF(); |
| 911 } | 865 } |
| 912 | 866 |
| 913 void ChunkDemuxer::SetDuration(double duration) { | 867 void ChunkDemuxer::SetDuration(double duration) { |
| 914 base::AutoLock auto_lock(lock_); | 868 base::AutoLock auto_lock(lock_); |
| 915 DVLOG(1) << "SetDuration(" << duration << ")"; | 869 DVLOG(1) << "set_duration(" << duration << ")"; |
| 916 DCHECK_GE(duration, 0); | 870 DCHECK_GE(duration, 0); |
| 917 | 871 |
| 918 if (duration == GetDuration_Locked()) | 872 if (duration == GetDuration_Locked()) return; |
| 919 return; | |
| 920 | 873 |
| 921 // Compute & bounds check the TimeDelta representation of duration. | 874 // Compute & bounds check the TimeDelta representation of duration. |
| 922 // This can be different if the value of |duration| doesn't fit the range or | 875 // This can be different if the value of |duration| doesn't fit the range or |
| 923 // precision of base::TimeDelta. | 876 // precision of base::TimeDelta. |
| 924 base::TimeDelta min_duration = base::TimeDelta::FromInternalValue(1); | 877 base::TimeDelta min_duration = base::TimeDelta::FromInternalValue(1); |
| 925 base::TimeDelta max_duration = | 878 base::TimeDelta max_duration = |
| 926 base::TimeDelta::FromInternalValue(kint64max - 1); | 879 base::TimeDelta::FromInternalValue(kint64max - 1); |
| 927 double min_duration_in_seconds = min_duration.InSecondsF(); | 880 double min_duration_in_seconds = min_duration.InSecondsF(); |
| 928 double max_duration_in_seconds = max_duration.InSecondsF(); | 881 double max_duration_in_seconds = max_duration.InSecondsF(); |
| 929 | 882 |
| 930 base::TimeDelta duration_td; | 883 base::TimeDelta duration_td; |
| 931 if (duration == std::numeric_limits<double>::infinity()) { | 884 if (duration == std::numeric_limits<double>::infinity()) { |
| 932 duration_td = media::kInfiniteDuration(); | 885 duration_td = media::kInfiniteDuration(); |
| 933 } else if (duration < min_duration_in_seconds) { | 886 } else if (duration < min_duration_in_seconds) { |
| 934 duration_td = min_duration; | 887 duration_td = min_duration; |
| 935 } else if (duration > max_duration_in_seconds) { | 888 } else if (duration > max_duration_in_seconds) { |
| 936 duration_td = max_duration; | 889 duration_td = max_duration; |
| 937 } else { | 890 } else { |
| 938 duration_td = base::TimeDelta::FromMicroseconds( | 891 duration_td = base::TimeDelta::FromMicroseconds( |
| 939 duration * base::Time::kMicrosecondsPerSecond); | 892 duration * base::Time::kMicrosecondsPerSecond); |
| 940 } | 893 } |
| 941 | 894 |
| 942 DCHECK(duration_td > base::TimeDelta()); | 895 DCHECK(duration_td > base::TimeDelta()); |
| 943 | 896 |
| 944 user_specified_duration_ = duration; | 897 user_specified_duration_ = duration; |
| 945 duration_ = duration_td; | 898 duration_ = duration_td; |
| 946 host_->SetDuration(duration_); | 899 host_->SetDuration(duration_); |
| 947 | 900 |
| 948 if (audio_) | 901 if (audio_) audio_->Onset_duration(duration_); |
| 949 audio_->OnSetDuration(duration_); | |
| 950 | 902 |
| 951 if (video_) | 903 if (video_) video_->Onset_duration(duration_); |
| 952 video_->OnSetDuration(duration_); | |
| 953 } | 904 } |
| 954 | 905 |
| 955 bool ChunkDemuxer::SetTimestampOffset(const std::string& id, TimeDelta offset) { | 906 bool ChunkDemuxer::SetTimestampOffset(const std::string& id, TimeDelta offset) { |
| 956 base::AutoLock auto_lock(lock_); | 907 base::AutoLock auto_lock(lock_); |
| 957 DVLOG(1) << "SetTimestampOffset(" << id << ", " << offset.InSecondsF() << ")"; | 908 DVLOG(1) << "set_timestampOffset(" << id << ", " << offset.InSecondsF() |
| 909 << ")"; |
| 958 CHECK(IsValidId(id)); | 910 CHECK(IsValidId(id)); |
| 959 | 911 |
| 960 return source_state_map_[id]->SetTimestampOffset(offset); | 912 return source_state_map_[id]->set_timestampOffset(offset); |
| 961 } | 913 } |
| 962 | 914 |
| 963 void ChunkDemuxer::EndOfStream(PipelineStatus status) { | 915 void ChunkDemuxer::EndOfStream(PipelineStatus status) { |
| 964 DVLOG(1) << "EndOfStream(" << status << ")"; | 916 DVLOG(1) << "EndOfStream(" << status << ")"; |
| 965 PipelineStatusCB cb; | 917 PipelineStatusCB cb; |
| 966 { | 918 { |
| 967 base::AutoLock auto_lock(lock_); | 919 base::AutoLock auto_lock(lock_); |
| 968 DCHECK_NE(state_, WAITING_FOR_INIT); | 920 DCHECK_NE(state_, WAITING_FOR_INIT); |
| 969 DCHECK_NE(state_, ENDED); | 921 DCHECK_NE(state_, ENDED); |
| 970 | 922 |
| 971 if (state_ == SHUTDOWN || state_ == PARSE_ERROR) | 923 if (state_ == SHUTDOWN || state_ == PARSE_ERROR) return; |
| 972 return; | |
| 973 | 924 |
| 974 if (state_ == INITIALIZING) { | 925 if (state_ == INITIALIZING) { |
| 975 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); | 926 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); |
| 976 return; | 927 return; |
| 977 } | 928 } |
| 978 | 929 |
| 979 bool old_seek_pending = IsSeekPending_Locked(); | 930 bool old_seek_pending = IsSeekPending_Locked(); |
| 980 if (audio_) | 931 if (audio_) audio_->EndOfStream(); |
| 981 audio_->EndOfStream(); | |
| 982 | 932 |
| 983 if (video_) | 933 if (video_) video_->EndOfStream(); |
| 984 video_->EndOfStream(); | |
| 985 | 934 |
| 986 // Give a chance to resume the pending seek process. | 935 // Give a chance to resume the pending seek process. |
| 987 if (status != PIPELINE_OK) { | 936 if (status != PIPELINE_OK) { |
| 988 ReportError_Locked(status); | 937 ReportError_Locked(status); |
| 989 return; | 938 return; |
| 990 } | 939 } |
| 991 | 940 |
| 992 ChangeState_Locked(ENDED); | 941 ChangeState_Locked(ENDED); |
| 993 DecreaseDurationIfNecessary(); | 942 DecreaseDurationIfNecessary(); |
| 994 | 943 |
| 995 if (old_seek_pending && !IsSeekPending_Locked() && !seek_cb_.is_null()) | 944 if (old_seek_pending && !IsSeekPending_Locked() && !seek_cb_.is_null()) |
| 996 std::swap(cb, seek_cb_); | 945 std::swap(cb, seek_cb_); |
| 997 } | 946 } |
| 998 | 947 |
| 999 if (!cb.is_null()) | 948 if (!cb.is_null()) cb.Run(PIPELINE_OK); |
| 1000 cb.Run(PIPELINE_OK); | |
| 1001 } | 949 } |
| 1002 | 950 |
| 1003 void ChunkDemuxer::Shutdown() { | 951 void ChunkDemuxer::Shutdown() { |
| 1004 DVLOG(1) << "Shutdown()"; | 952 DVLOG(1) << "Shutdown()"; |
| 1005 PipelineStatusCB cb; | 953 PipelineStatusCB cb; |
| 1006 { | 954 { |
| 1007 base::AutoLock auto_lock(lock_); | 955 base::AutoLock auto_lock(lock_); |
| 1008 | 956 |
| 1009 if (state_ == SHUTDOWN) | 957 if (state_ == SHUTDOWN) return; |
| 1010 return; | |
| 1011 | 958 |
| 1012 std::swap(cb, seek_cb_); | 959 std::swap(cb, seek_cb_); |
| 1013 | 960 |
| 1014 if (audio_) | 961 if (audio_) audio_->Shutdown(); |
| 1015 audio_->Shutdown(); | |
| 1016 | 962 |
| 1017 if (video_) | 963 if (video_) video_->Shutdown(); |
| 1018 video_->Shutdown(); | |
| 1019 | 964 |
| 1020 ChangeState_Locked(SHUTDOWN); | 965 ChangeState_Locked(SHUTDOWN); |
| 1021 } | 966 } |
| 1022 | 967 |
| 1023 if (!cb.is_null()) | 968 if (!cb.is_null()) cb.Run(PIPELINE_ERROR_ABORT); |
| 1024 cb.Run(PIPELINE_ERROR_ABORT); | |
| 1025 } | 969 } |
| 1026 | 970 |
| 1027 void ChunkDemuxer::ChangeState_Locked(State new_state) { | 971 void ChunkDemuxer::ChangeState_Locked(State new_state) { |
| 1028 lock_.AssertAcquired(); | 972 lock_.AssertAcquired(); |
| 1029 DVLOG(1) << "ChunkDemuxer::ChangeState_Locked() : " | 973 DVLOG(1) << "ChunkDemuxer::ChangeState_Locked() : " << state_ << " -> " |
| 1030 << state_ << " -> " << new_state; | 974 << new_state; |
| 1031 state_ = new_state; | 975 state_ = new_state; |
| 1032 } | 976 } |
| 1033 | 977 |
| 1034 ChunkDemuxer::~ChunkDemuxer() { | 978 ChunkDemuxer::~ChunkDemuxer() { |
| 1035 DCHECK_NE(state_, INITIALIZED); | 979 DCHECK_NE(state_, INITIALIZED); |
| 1036 for (SourceStateMap::iterator it = source_state_map_.begin(); | 980 for (SourceStateMap::iterator it = source_state_map_.begin(); |
| 1037 it != source_state_map_.end(); ++it) { | 981 it != source_state_map_.end(); ++it) { |
| 1038 delete it->second; | 982 delete it->second; |
| 1039 } | 983 } |
| 1040 source_state_map_.clear(); | 984 source_state_map_.clear(); |
| 1041 } | 985 } |
| 1042 | 986 |
| 1043 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) { | 987 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) { |
| 1044 DVLOG(1) << "ReportError_Locked(" << error << ")"; | 988 DVLOG(1) << "ReportError_Locked(" << error << ")"; |
| 1045 lock_.AssertAcquired(); | 989 lock_.AssertAcquired(); |
| 1046 DCHECK_NE(error, PIPELINE_OK); | 990 DCHECK_NE(error, PIPELINE_OK); |
| 1047 | 991 |
| 1048 ChangeState_Locked(PARSE_ERROR); | 992 ChangeState_Locked(PARSE_ERROR); |
| 1049 | 993 |
| 1050 PipelineStatusCB cb; | 994 PipelineStatusCB cb; |
| 1051 | 995 |
| 1052 if (!init_cb_.is_null()) { | 996 if (!init_cb_.is_null()) { |
| 1053 std::swap(cb, init_cb_); | 997 std::swap(cb, init_cb_); |
| 1054 } else { | 998 } else { |
| 1055 if (!seek_cb_.is_null()) | 999 if (!seek_cb_.is_null()) std::swap(cb, seek_cb_); |
| 1056 std::swap(cb, seek_cb_); | |
| 1057 | 1000 |
| 1058 if (audio_) | 1001 if (audio_) audio_->Shutdown(); |
| 1059 audio_->Shutdown(); | |
| 1060 | 1002 |
| 1061 if (video_) | 1003 if (video_) video_->Shutdown(); |
| 1062 video_->Shutdown(); | |
| 1063 } | 1004 } |
| 1064 | 1005 |
| 1065 if (!cb.is_null()) { | 1006 if (!cb.is_null()) { |
| 1066 base::AutoUnlock auto_unlock(lock_); | 1007 base::AutoUnlock auto_unlock(lock_); |
| 1067 cb.Run(error); | 1008 cb.Run(error); |
| 1068 return; | 1009 return; |
| 1069 } | 1010 } |
| 1070 | 1011 |
| 1071 base::AutoUnlock auto_unlock(lock_); | 1012 base::AutoUnlock auto_unlock(lock_); |
| 1072 host_->OnDemuxerError(error); | 1013 host_->OnDemuxerError(error); |
| 1073 } | 1014 } |
| 1074 | 1015 |
| 1075 bool ChunkDemuxer::IsSeekPending_Locked() const { | 1016 bool ChunkDemuxer::IsSeekPending_Locked() const { |
| 1076 lock_.AssertAcquired(); | 1017 lock_.AssertAcquired(); |
| 1077 bool seek_pending = false; | 1018 bool seek_pending = false; |
| 1078 | 1019 |
| 1079 if (audio_) | 1020 if (audio_) seek_pending = audio_->IsSeekPending(); |
| 1080 seek_pending = audio_->IsSeekPending(); | |
| 1081 | 1021 |
| 1082 if (!seek_pending && video_) | 1022 if (!seek_pending && video_) seek_pending = video_->IsSeekPending(); |
| 1083 seek_pending = video_->IsSeekPending(); | |
| 1084 | 1023 |
| 1085 return seek_pending; | 1024 return seek_pending; |
| 1086 } | 1025 } |
| 1087 | 1026 |
| 1088 void ChunkDemuxer::OnSourceInitDone(bool success, TimeDelta duration) { | 1027 void ChunkDemuxer::OnSourceInitDone(bool success, TimeDelta duration) { |
| 1089 DVLOG(1) << "OnSourceInitDone(" << success << ", " | 1028 DVLOG(1) << "OnSourceInitDone(" << success << ", " << duration.InSecondsF() |
| 1090 << duration.InSecondsF() << ")"; | 1029 << ")"; |
| 1091 lock_.AssertAcquired(); | 1030 lock_.AssertAcquired(); |
| 1092 DCHECK_EQ(state_, INITIALIZING); | 1031 DCHECK_EQ(state_, INITIALIZING); |
| 1093 if (!success || (!audio_ && !video_)) { | 1032 if (!success || (!audio_ && !video_)) { |
| 1094 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); | 1033 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); |
| 1095 return; | 1034 return; |
| 1096 } | 1035 } |
| 1097 | 1036 |
| 1098 if (duration != base::TimeDelta() && duration_ == kNoTimestamp()) | 1037 if (duration != base::TimeDelta() && duration_ == kNoTimestamp()) |
| 1099 UpdateDuration(duration); | 1038 UpdateDuration(duration); |
| 1100 | 1039 |
| 1101 // Wait until all streams have initialized. | 1040 // Wait until all streams have initialized. |
| 1102 if ((!source_id_audio_.empty() && !audio_) || | 1041 if ((!source_id_audio_.empty() && !audio_) || |
| 1103 (!source_id_video_.empty() && !video_)) | 1042 (!source_id_video_.empty() && !video_)) |
| 1104 return; | 1043 return; |
| 1105 | 1044 |
| 1106 if (audio_) | 1045 if (audio_) audio_->Seek(TimeDelta()); |
| 1107 audio_->Seek(TimeDelta()); | |
| 1108 | 1046 |
| 1109 if (video_) | 1047 if (video_) video_->Seek(TimeDelta()); |
| 1110 video_->Seek(TimeDelta()); | |
| 1111 | 1048 |
| 1112 if (duration_ == kNoTimestamp()) | 1049 if (duration_ == kNoTimestamp()) duration_ = kInfiniteDuration(); |
| 1113 duration_ = kInfiniteDuration(); | |
| 1114 | 1050 |
| 1115 // The demuxer is now initialized after the |start_timestamp_| was set. | 1051 // The demuxer is now initialized after the |start_timestamp_| was set. |
| 1116 ChangeState_Locked(INITIALIZED); | 1052 ChangeState_Locked(INITIALIZED); |
| 1117 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); | 1053 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); |
| 1118 } | 1054 } |
| 1119 | 1055 |
| 1120 bool ChunkDemuxer::OnNewConfigs(bool has_audio, bool has_video, | 1056 bool ChunkDemuxer::OnNewConfigs(bool has_audio, bool has_video, |
| 1121 const AudioDecoderConfig& audio_config, | 1057 const AudioDecoderConfig& audio_config, |
| 1122 const VideoDecoderConfig& video_config) { | 1058 const VideoDecoderConfig& video_config) { |
| 1123 DVLOG(1) << "OnNewConfigs(" << has_audio << ", " << has_video | 1059 DVLOG(1) << "OnNewConfigs(" << has_audio << ", " << has_video << ", " |
| 1124 << ", " << audio_config.IsValidConfig() | 1060 << audio_config.IsValidConfig() << ", " |
| 1125 << ", " << video_config.IsValidConfig() << ")"; | 1061 << video_config.IsValidConfig() << ")"; |
| 1126 lock_.AssertAcquired(); | 1062 lock_.AssertAcquired(); |
| 1127 | 1063 |
| 1128 if (!audio_config.IsValidConfig() && !video_config.IsValidConfig()) { | 1064 if (!audio_config.IsValidConfig() && !video_config.IsValidConfig()) { |
| 1129 DVLOG(1) << "OnNewConfigs() : Audio & video config are not valid!"; | 1065 DVLOG(1) << "OnNewConfigs() : Audio & video config are not valid!"; |
| 1130 return false; | 1066 return false; |
| 1131 } | 1067 } |
| 1132 | 1068 |
| 1133 // Signal an error if we get configuration info for stream types that weren't | 1069 // Signal an error if we get configuration info for stream types that weren't |
| 1134 // specified in AddId() or more configs after a stream is initialized. | 1070 // specified in AddId() or more configs after a stream is initialized. |
| 1135 // Only allow a single audio config for now. | 1071 // Only allow a single audio config for now. |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1172 } | 1108 } |
| 1173 | 1109 |
| 1174 DVLOG(1) << "OnNewConfigs() : " << (success ? "success" : "failed"); | 1110 DVLOG(1) << "OnNewConfigs() : " << (success ? "success" : "failed"); |
| 1175 return success; | 1111 return success; |
| 1176 } | 1112 } |
| 1177 | 1113 |
| 1178 bool ChunkDemuxer::OnAudioBuffers(const StreamParser::BufferQueue& buffers) { | 1114 bool ChunkDemuxer::OnAudioBuffers(const StreamParser::BufferQueue& buffers) { |
| 1179 lock_.AssertAcquired(); | 1115 lock_.AssertAcquired(); |
| 1180 DCHECK_NE(state_, SHUTDOWN); | 1116 DCHECK_NE(state_, SHUTDOWN); |
| 1181 | 1117 |
| 1182 if (!audio_) | 1118 if (!audio_) return false; |
| 1183 return false; | |
| 1184 | 1119 |
| 1185 CHECK(IsValidId(source_id_audio_)); | 1120 CHECK(IsValidId(source_id_audio_)); |
| 1186 if (!audio_->Append(buffers)) | 1121 if (!audio_->Append(buffers)) return false; |
| 1187 return false; | |
| 1188 | 1122 |
| 1189 IncreaseDurationIfNecessary(buffers, audio_.get()); | 1123 IncreaseDurationIfNecessary(buffers, audio_.get()); |
| 1190 return true; | 1124 return true; |
| 1191 } | 1125 } |
| 1192 | 1126 |
| 1193 bool ChunkDemuxer::OnVideoBuffers(const StreamParser::BufferQueue& buffers) { | 1127 bool ChunkDemuxer::OnVideoBuffers(const StreamParser::BufferQueue& buffers) { |
| 1194 lock_.AssertAcquired(); | 1128 lock_.AssertAcquired(); |
| 1195 DCHECK_NE(state_, SHUTDOWN); | 1129 DCHECK_NE(state_, SHUTDOWN); |
| 1196 | 1130 |
| 1197 if (!video_) | 1131 if (!video_) return false; |
| 1198 return false; | |
| 1199 | 1132 |
| 1200 CHECK(IsValidId(source_id_video_)); | 1133 CHECK(IsValidId(source_id_video_)); |
| 1201 if (!video_->Append(buffers)) | 1134 if (!video_->Append(buffers)) return false; |
| 1202 return false; | |
| 1203 | 1135 |
| 1204 IncreaseDurationIfNecessary(buffers, video_.get()); | 1136 IncreaseDurationIfNecessary(buffers, video_.get()); |
| 1205 return true; | 1137 return true; |
| 1206 } | 1138 } |
| 1207 | 1139 |
| 1208 bool ChunkDemuxer::OnTextBuffers( | 1140 bool ChunkDemuxer::OnTextBuffers(TextTrack* text_track, |
| 1209 TextTrack* text_track, | 1141 const StreamParser::BufferQueue& buffers) { |
| 1210 const StreamParser::BufferQueue& buffers) { | |
| 1211 lock_.AssertAcquired(); | 1142 lock_.AssertAcquired(); |
| 1212 DCHECK_NE(state_, SHUTDOWN); | 1143 DCHECK_NE(state_, SHUTDOWN); |
| 1213 | 1144 |
| 1214 // TODO(matthewjheaney): IncreaseDurationIfNecessary | 1145 // TODO(matthewjheaney): IncreaseDurationIfNecessary |
| 1215 | 1146 |
| 1216 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); | 1147 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); |
| 1217 itr != buffers.end(); ++itr) { | 1148 itr != buffers.end(); ++itr) { |
| 1218 const StreamParserBuffer* const buffer = itr->get(); | 1149 const StreamParserBuffer* const buffer = itr->get(); |
| 1219 const base::TimeDelta start = buffer->GetTimestamp(); | 1150 const base::TimeDelta start = buffer->get_timestamp(); |
| 1220 const base::TimeDelta end = start + buffer->GetDuration(); | 1151 const base::TimeDelta end = start + buffer->get_duration(); |
| 1221 | 1152 |
| 1222 std::string id, settings, content; | 1153 std::string id, settings, content; |
| 1223 | 1154 |
| 1224 WebMWebVTTParser::Parse(buffer->GetData(), | 1155 WebMWebVTTParser::Parse(buffer->get_data(), buffer->get_data_size(), &id, |
| 1225 buffer->GetDataSize(), | 1156 &settings, &content); |
| 1226 &id, &settings, &content); | |
| 1227 | 1157 |
| 1228 text_track->addWebVTTCue(start, end, id, content, settings); | 1158 text_track->addWebVTTCue(start, end, id, content, settings); |
| 1229 } | 1159 } |
| 1230 | 1160 |
| 1231 return true; | 1161 return true; |
| 1232 } | 1162 } |
| 1233 | 1163 |
| 1234 // TODO(acolwell): Remove bool from StreamParser::NeedKeyCB so that | 1164 // TODO(acolwell): Remove bool from StreamParser::NeedKeyCB so that |
| 1235 // this method can be removed and need_key_cb_ can be passed directly | 1165 // this method can be removed and need_key_cb_ can be passed directly |
| 1236 // to the parser. | 1166 // to the parser. |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1262 } | 1192 } |
| 1263 | 1193 |
| 1264 void ChunkDemuxer::UpdateDuration(base::TimeDelta new_duration) { | 1194 void ChunkDemuxer::UpdateDuration(base::TimeDelta new_duration) { |
| 1265 DCHECK(duration_ != new_duration); | 1195 DCHECK(duration_ != new_duration); |
| 1266 user_specified_duration_ = -1; | 1196 user_specified_duration_ = -1; |
| 1267 duration_ = new_duration; | 1197 duration_ = new_duration; |
| 1268 host_->SetDuration(new_duration); | 1198 host_->SetDuration(new_duration); |
| 1269 } | 1199 } |
| 1270 | 1200 |
| 1271 void ChunkDemuxer::IncreaseDurationIfNecessary( | 1201 void ChunkDemuxer::IncreaseDurationIfNecessary( |
| 1272 const StreamParser::BufferQueue& buffers, | 1202 const StreamParser::BufferQueue& buffers, ChunkDemuxerStream* stream) { |
| 1273 ChunkDemuxerStream* stream) { | |
| 1274 DCHECK(!buffers.empty()); | 1203 DCHECK(!buffers.empty()); |
| 1275 if (buffers.back()->GetTimestamp() <= duration_) | 1204 if (buffers.back()->get_timestamp() <= duration_) return; |
| 1276 return; | |
| 1277 | 1205 |
| 1278 Ranges<TimeDelta> ranges = stream->GetBufferedRanges(kInfiniteDuration()); | 1206 Ranges<TimeDelta> ranges = stream->GetBufferedRanges(kInfiniteDuration()); |
| 1279 DCHECK_GT(ranges.size(), 0u); | 1207 DCHECK_GT(ranges.size(), 0u); |
| 1280 | 1208 |
| 1281 base::TimeDelta last_timestamp_buffered = ranges.end(ranges.size() - 1); | 1209 base::TimeDelta last_timestamp_buffered = ranges.end(ranges.size() - 1); |
| 1282 if (last_timestamp_buffered > duration_) | 1210 if (last_timestamp_buffered > duration_) |
| 1283 UpdateDuration(last_timestamp_buffered); | 1211 UpdateDuration(last_timestamp_buffered); |
| 1284 } | 1212 } |
| 1285 | 1213 |
| 1286 void ChunkDemuxer::DecreaseDurationIfNecessary() { | 1214 void ChunkDemuxer::DecreaseDurationIfNecessary() { |
| 1287 Ranges<TimeDelta> ranges = GetBufferedRanges(); | 1215 Ranges<TimeDelta> ranges = GetBufferedRanges(); |
| 1288 if (ranges.size() == 0u) | 1216 if (ranges.size() == 0u) return; |
| 1289 return; | |
| 1290 | 1217 |
| 1291 base::TimeDelta last_timestamp_buffered = ranges.end(ranges.size() - 1); | 1218 base::TimeDelta last_timestamp_buffered = ranges.end(ranges.size() - 1); |
| 1292 if (last_timestamp_buffered < duration_) | 1219 if (last_timestamp_buffered < duration_) |
| 1293 UpdateDuration(last_timestamp_buffered); | 1220 UpdateDuration(last_timestamp_buffered); |
| 1294 } | 1221 } |
| 1295 | 1222 |
| 1296 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges() const { | 1223 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges() const { |
| 1297 if (audio_ && !video_) | 1224 if (audio_ && !video_) |
| 1298 return audio_->GetBufferedRanges(duration_); | 1225 return audio_->GetBufferedRanges(duration_); |
| 1299 else if (!audio_ && video_) | 1226 else if (!audio_ && video_) |
| 1300 return video_->GetBufferedRanges(duration_); | 1227 return video_->GetBufferedRanges(duration_); |
| 1301 return ComputeIntersection(); | 1228 return ComputeIntersection(); |
| 1302 } | 1229 } |
| 1303 | 1230 |
| 1304 } // namespace media | 1231 } // namespace media |
| OLD | NEW |