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

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

Issue 65803002: Replace MessageLoopProxy with SingleThreadTaskRunner for media/filters/ + associated code. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « media/filters/ffmpeg_demuxer.h ('k') | media/filters/ffmpeg_video_decoder.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/filters/ffmpeg_demuxer.h" 5 #include "media/filters/ffmpeg_demuxer.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <string> 8 #include <string>
9 9
10 #include "base/base64.h" 10 #include "base/base64.h"
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/callback.h" 12 #include "base/callback.h"
13 #include "base/callback_helpers.h" 13 #include "base/callback_helpers.h"
14 #include "base/memory/scoped_ptr.h" 14 #include "base/memory/scoped_ptr.h"
15 #include "base/message_loop/message_loop.h" 15 #include "base/message_loop/message_loop_proxy.h"
16 #include "base/metrics/sparse_histogram.h" 16 #include "base/metrics/sparse_histogram.h"
17 #include "base/strings/string_util.h" 17 #include "base/strings/string_util.h"
18 #include "base/strings/stringprintf.h" 18 #include "base/strings/stringprintf.h"
19 #include "base/sys_byteorder.h" 19 #include "base/sys_byteorder.h"
20 #include "base/task_runner_util.h" 20 #include "base/task_runner_util.h"
21 #include "base/time/time.h" 21 #include "base/time/time.h"
22 #include "media/base/audio_decoder_config.h" 22 #include "media/base/audio_decoder_config.h"
23 #include "media/base/bind_to_loop.h" 23 #include "media/base/bind_to_loop.h"
24 #include "media/base/decoder_buffer.h" 24 #include "media/base/decoder_buffer.h"
25 #include "media/base/decrypt_config.h" 25 #include "media/base/decrypt_config.h"
26 #include "media/base/limits.h" 26 #include "media/base/limits.h"
27 #include "media/base/media_log.h" 27 #include "media/base/media_log.h"
28 #include "media/base/video_decoder_config.h" 28 #include "media/base/video_decoder_config.h"
29 #include "media/ffmpeg/ffmpeg_common.h" 29 #include "media/ffmpeg/ffmpeg_common.h"
30 #include "media/filters/ffmpeg_glue.h" 30 #include "media/filters/ffmpeg_glue.h"
31 #include "media/filters/ffmpeg_h264_to_annex_b_bitstream_converter.h" 31 #include "media/filters/ffmpeg_h264_to_annex_b_bitstream_converter.h"
32 #include "media/filters/webvtt_util.h" 32 #include "media/filters/webvtt_util.h"
33 #include "media/webm/webm_crypto_helpers.h" 33 #include "media/webm/webm_crypto_helpers.h"
34 34
35 namespace media { 35 namespace media {
36 36
37 // 37 //
38 // FFmpegDemuxerStream 38 // FFmpegDemuxerStream
39 // 39 //
40 FFmpegDemuxerStream::FFmpegDemuxerStream( 40 FFmpegDemuxerStream::FFmpegDemuxerStream(
41 FFmpegDemuxer* demuxer, 41 FFmpegDemuxer* demuxer,
42 AVStream* stream) 42 AVStream* stream)
43 : demuxer_(demuxer), 43 : demuxer_(demuxer),
44 message_loop_(base::MessageLoopProxy::current()), 44 task_runner_(base::MessageLoopProxy::current()),
45 stream_(stream), 45 stream_(stream),
46 type_(UNKNOWN), 46 type_(UNKNOWN),
47 end_of_stream_(false), 47 end_of_stream_(false),
48 last_packet_timestamp_(kNoTimestamp()), 48 last_packet_timestamp_(kNoTimestamp()),
49 bitstream_converter_enabled_(false) { 49 bitstream_converter_enabled_(false) {
50 DCHECK(demuxer_); 50 DCHECK(demuxer_);
51 51
52 bool is_encrypted = false; 52 bool is_encrypted = false;
53 53
54 // Determine our media format. 54 // Determine our media format.
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
92 DCHECK(!enc_key_id.empty()); 92 DCHECK(!enc_key_id.empty());
93 if (enc_key_id.empty()) 93 if (enc_key_id.empty())
94 return; 94 return;
95 95
96 encryption_key_id_.assign(enc_key_id); 96 encryption_key_id_.assign(enc_key_id);
97 demuxer_->FireNeedKey(kWebMEncryptInitDataType, enc_key_id); 97 demuxer_->FireNeedKey(kWebMEncryptInitDataType, enc_key_id);
98 } 98 }
99 } 99 }
100 100
101 void FFmpegDemuxerStream::EnqueuePacket(ScopedAVPacket packet) { 101 void FFmpegDemuxerStream::EnqueuePacket(ScopedAVPacket packet) {
102 DCHECK(message_loop_->BelongsToCurrentThread()); 102 DCHECK(task_runner_->BelongsToCurrentThread());
103 103
104 if (!demuxer_ || end_of_stream_) { 104 if (!demuxer_ || end_of_stream_) {
105 NOTREACHED() << "Attempted to enqueue packet on a stopped stream"; 105 NOTREACHED() << "Attempted to enqueue packet on a stopped stream";
106 return; 106 return;
107 } 107 }
108 108
109 // Convert the packet if there is a bitstream filter. 109 // Convert the packet if there is a bitstream filter.
110 if (packet->data && bitstream_converter_enabled_ && 110 if (packet->data && bitstream_converter_enabled_ &&
111 !bitstream_converter_->ConvertPacket(packet.get())) { 111 !bitstream_converter_->ConvertPacket(packet.get())) {
112 LOG(ERROR) << "Format conversion failed."; 112 LOG(ERROR) << "Format conversion failed.";
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
194 buffered_ranges_.Add(last_packet_timestamp_, buffer->timestamp()); 194 buffered_ranges_.Add(last_packet_timestamp_, buffer->timestamp());
195 demuxer_->NotifyBufferingChanged(); 195 demuxer_->NotifyBufferingChanged();
196 } 196 }
197 last_packet_timestamp_ = buffer->timestamp(); 197 last_packet_timestamp_ = buffer->timestamp();
198 198
199 buffer_queue_.Push(buffer); 199 buffer_queue_.Push(buffer);
200 SatisfyPendingRead(); 200 SatisfyPendingRead();
201 } 201 }
202 202
203 void FFmpegDemuxerStream::SetEndOfStream() { 203 void FFmpegDemuxerStream::SetEndOfStream() {
204 DCHECK(message_loop_->BelongsToCurrentThread()); 204 DCHECK(task_runner_->BelongsToCurrentThread());
205 end_of_stream_ = true; 205 end_of_stream_ = true;
206 SatisfyPendingRead(); 206 SatisfyPendingRead();
207 } 207 }
208 208
209 void FFmpegDemuxerStream::FlushBuffers() { 209 void FFmpegDemuxerStream::FlushBuffers() {
210 DCHECK(message_loop_->BelongsToCurrentThread()); 210 DCHECK(task_runner_->BelongsToCurrentThread());
211 DCHECK(read_cb_.is_null()) << "There should be no pending read"; 211 DCHECK(read_cb_.is_null()) << "There should be no pending read";
212 buffer_queue_.Clear(); 212 buffer_queue_.Clear();
213 end_of_stream_ = false; 213 end_of_stream_ = false;
214 last_packet_timestamp_ = kNoTimestamp(); 214 last_packet_timestamp_ = kNoTimestamp();
215 } 215 }
216 216
217 void FFmpegDemuxerStream::Stop() { 217 void FFmpegDemuxerStream::Stop() {
218 DCHECK(message_loop_->BelongsToCurrentThread()); 218 DCHECK(task_runner_->BelongsToCurrentThread());
219 buffer_queue_.Clear(); 219 buffer_queue_.Clear();
220 if (!read_cb_.is_null()) { 220 if (!read_cb_.is_null()) {
221 base::ResetAndReturn(&read_cb_).Run( 221 base::ResetAndReturn(&read_cb_).Run(
222 DemuxerStream::kOk, DecoderBuffer::CreateEOSBuffer()); 222 DemuxerStream::kOk, DecoderBuffer::CreateEOSBuffer());
223 } 223 }
224 demuxer_ = NULL; 224 demuxer_ = NULL;
225 stream_ = NULL; 225 stream_ = NULL;
226 end_of_stream_ = true; 226 end_of_stream_ = true;
227 } 227 }
228 228
229 base::TimeDelta FFmpegDemuxerStream::duration() { 229 base::TimeDelta FFmpegDemuxerStream::duration() {
230 return duration_; 230 return duration_;
231 } 231 }
232 232
233 DemuxerStream::Type FFmpegDemuxerStream::type() { 233 DemuxerStream::Type FFmpegDemuxerStream::type() {
234 DCHECK(message_loop_->BelongsToCurrentThread()); 234 DCHECK(task_runner_->BelongsToCurrentThread());
235 return type_; 235 return type_;
236 } 236 }
237 237
238 void FFmpegDemuxerStream::Read(const ReadCB& read_cb) { 238 void FFmpegDemuxerStream::Read(const ReadCB& read_cb) {
239 DCHECK(message_loop_->BelongsToCurrentThread()); 239 DCHECK(task_runner_->BelongsToCurrentThread());
240 CHECK(read_cb_.is_null()) << "Overlapping reads are not supported"; 240 CHECK(read_cb_.is_null()) << "Overlapping reads are not supported";
241 read_cb_ = BindToCurrentLoop(read_cb); 241 read_cb_ = BindToCurrentLoop(read_cb);
242 242
243 // Don't accept any additional reads if we've been told to stop. 243 // Don't accept any additional reads if we've been told to stop.
244 // The |demuxer_| may have been destroyed in the pipeline thread. 244 // The |demuxer_| may have been destroyed in the pipeline thread.
245 // 245 //
246 // TODO(scherkus): it would be cleaner to reply with an error message. 246 // TODO(scherkus): it would be cleaner to reply with an error message.
247 if (!demuxer_) { 247 if (!demuxer_) {
248 base::ResetAndReturn(&read_cb_).Run( 248 base::ResetAndReturn(&read_cb_).Run(
249 DemuxerStream::kOk, DecoderBuffer::CreateEOSBuffer()); 249 DemuxerStream::kOk, DecoderBuffer::CreateEOSBuffer());
250 return; 250 return;
251 } 251 }
252 252
253 SatisfyPendingRead(); 253 SatisfyPendingRead();
254 } 254 }
255 255
256 void FFmpegDemuxerStream::EnableBitstreamConverter() { 256 void FFmpegDemuxerStream::EnableBitstreamConverter() {
257 DCHECK(message_loop_->BelongsToCurrentThread()); 257 DCHECK(task_runner_->BelongsToCurrentThread());
258 CHECK(bitstream_converter_.get()); 258 CHECK(bitstream_converter_.get());
259 bitstream_converter_enabled_ = true; 259 bitstream_converter_enabled_ = true;
260 } 260 }
261 261
262 AudioDecoderConfig FFmpegDemuxerStream::audio_decoder_config() { 262 AudioDecoderConfig FFmpegDemuxerStream::audio_decoder_config() {
263 DCHECK(message_loop_->BelongsToCurrentThread()); 263 DCHECK(task_runner_->BelongsToCurrentThread());
264 CHECK_EQ(type_, AUDIO); 264 CHECK_EQ(type_, AUDIO);
265 return audio_config_; 265 return audio_config_;
266 } 266 }
267 267
268 VideoDecoderConfig FFmpegDemuxerStream::video_decoder_config() { 268 VideoDecoderConfig FFmpegDemuxerStream::video_decoder_config() {
269 DCHECK(message_loop_->BelongsToCurrentThread()); 269 DCHECK(task_runner_->BelongsToCurrentThread());
270 CHECK_EQ(type_, VIDEO); 270 CHECK_EQ(type_, VIDEO);
271 return video_config_; 271 return video_config_;
272 } 272 }
273 273
274 FFmpegDemuxerStream::~FFmpegDemuxerStream() { 274 FFmpegDemuxerStream::~FFmpegDemuxerStream() {
275 DCHECK(!demuxer_); 275 DCHECK(!demuxer_);
276 DCHECK(read_cb_.is_null()); 276 DCHECK(read_cb_.is_null());
277 DCHECK(buffer_queue_.IsEmpty()); 277 DCHECK(buffer_queue_.IsEmpty());
278 } 278 }
279 279
280 base::TimeDelta FFmpegDemuxerStream::GetElapsedTime() const { 280 base::TimeDelta FFmpegDemuxerStream::GetElapsedTime() const {
281 return ConvertStreamTimestamp(stream_->time_base, stream_->cur_dts); 281 return ConvertStreamTimestamp(stream_->time_base, stream_->cur_dts);
282 } 282 }
283 283
284 Ranges<base::TimeDelta> FFmpegDemuxerStream::GetBufferedRanges() const { 284 Ranges<base::TimeDelta> FFmpegDemuxerStream::GetBufferedRanges() const {
285 return buffered_ranges_; 285 return buffered_ranges_;
286 } 286 }
287 287
288 void FFmpegDemuxerStream::SatisfyPendingRead() { 288 void FFmpegDemuxerStream::SatisfyPendingRead() {
289 DCHECK(message_loop_->BelongsToCurrentThread()); 289 DCHECK(task_runner_->BelongsToCurrentThread());
290 if (!read_cb_.is_null()) { 290 if (!read_cb_.is_null()) {
291 if (!buffer_queue_.IsEmpty()) { 291 if (!buffer_queue_.IsEmpty()) {
292 base::ResetAndReturn(&read_cb_).Run( 292 base::ResetAndReturn(&read_cb_).Run(
293 DemuxerStream::kOk, buffer_queue_.Pop()); 293 DemuxerStream::kOk, buffer_queue_.Pop());
294 } else if (end_of_stream_) { 294 } else if (end_of_stream_) {
295 base::ResetAndReturn(&read_cb_).Run( 295 base::ResetAndReturn(&read_cb_).Run(
296 DemuxerStream::kOk, DecoderBuffer::CreateEOSBuffer()); 296 DemuxerStream::kOk, DecoderBuffer::CreateEOSBuffer());
297 } 297 }
298 } 298 }
299 299
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
341 if (timestamp == static_cast<int64>(AV_NOPTS_VALUE)) 341 if (timestamp == static_cast<int64>(AV_NOPTS_VALUE))
342 return kNoTimestamp(); 342 return kNoTimestamp();
343 343
344 return ConvertFromTimeBase(time_base, timestamp); 344 return ConvertFromTimeBase(time_base, timestamp);
345 } 345 }
346 346
347 // 347 //
348 // FFmpegDemuxer 348 // FFmpegDemuxer
349 // 349 //
350 FFmpegDemuxer::FFmpegDemuxer( 350 FFmpegDemuxer::FFmpegDemuxer(
351 const scoped_refptr<base::MessageLoopProxy>& message_loop, 351 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
352 DataSource* data_source, 352 DataSource* data_source,
353 const NeedKeyCB& need_key_cb, 353 const NeedKeyCB& need_key_cb,
354 const scoped_refptr<MediaLog>& media_log) 354 const scoped_refptr<MediaLog>& media_log)
355 : host_(NULL), 355 : host_(NULL),
356 message_loop_(message_loop), 356 task_runner_(task_runner),
357 weak_factory_(this), 357 weak_factory_(this),
358 blocking_thread_("FFmpegDemuxer"), 358 blocking_thread_("FFmpegDemuxer"),
359 pending_read_(false), 359 pending_read_(false),
360 pending_seek_(false), 360 pending_seek_(false),
361 data_source_(data_source), 361 data_source_(data_source),
362 media_log_(media_log), 362 media_log_(media_log),
363 bitrate_(0), 363 bitrate_(0),
364 start_time_(kNoTimestamp()), 364 start_time_(kNoTimestamp()),
365 audio_disabled_(false), 365 audio_disabled_(false),
366 text_enabled_(false), 366 text_enabled_(false),
367 duration_known_(false), 367 duration_known_(false),
368 url_protocol_(data_source, BindToLoop(message_loop_, base::Bind( 368 url_protocol_(data_source, BindToLoop(task_runner_, base::Bind(
369 &FFmpegDemuxer::OnDataSourceError, base::Unretained(this)))), 369 &FFmpegDemuxer::OnDataSourceError, base::Unretained(this)))),
370 need_key_cb_(need_key_cb) { 370 need_key_cb_(need_key_cb) {
371 DCHECK(message_loop_.get()); 371 DCHECK(task_runner_.get());
372 DCHECK(data_source_); 372 DCHECK(data_source_);
373 } 373 }
374 374
375 FFmpegDemuxer::~FFmpegDemuxer() {} 375 FFmpegDemuxer::~FFmpegDemuxer() {}
376 376
377 void FFmpegDemuxer::Stop(const base::Closure& callback) { 377 void FFmpegDemuxer::Stop(const base::Closure& callback) {
378 DCHECK(message_loop_->BelongsToCurrentThread()); 378 DCHECK(task_runner_->BelongsToCurrentThread());
379 url_protocol_.Abort(); 379 url_protocol_.Abort();
380 data_source_->Stop(BindToCurrentLoop(base::Bind( 380 data_source_->Stop(BindToCurrentLoop(base::Bind(
381 &FFmpegDemuxer::OnDataSourceStopped, weak_this_, 381 &FFmpegDemuxer::OnDataSourceStopped, weak_this_,
382 BindToCurrentLoop(callback)))); 382 BindToCurrentLoop(callback))));
383 data_source_ = NULL; 383 data_source_ = NULL;
384 } 384 }
385 385
386 void FFmpegDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) { 386 void FFmpegDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) {
387 DCHECK(message_loop_->BelongsToCurrentThread()); 387 DCHECK(task_runner_->BelongsToCurrentThread());
388 CHECK(!pending_seek_); 388 CHECK(!pending_seek_);
389 389
390 // TODO(scherkus): Inspect |pending_read_| and cancel IO via |blocking_url_|, 390 // TODO(scherkus): Inspect |pending_read_| and cancel IO via |blocking_url_|,
391 // otherwise we can end up waiting for a pre-seek read to complete even though 391 // otherwise we can end up waiting for a pre-seek read to complete even though
392 // we know we're going to drop it on the floor. 392 // we know we're going to drop it on the floor.
393 393
394 // Always seek to a timestamp less than or equal to the desired timestamp. 394 // Always seek to a timestamp less than or equal to the desired timestamp.
395 int flags = AVSEEK_FLAG_BACKWARD; 395 int flags = AVSEEK_FLAG_BACKWARD;
396 396
397 // Passing -1 as our stream index lets FFmpeg pick a default stream. FFmpeg 397 // Passing -1 as our stream index lets FFmpeg pick a default stream. FFmpeg
398 // will attempt to use the lowest-index video stream, if present, followed by 398 // will attempt to use the lowest-index video stream, if present, followed by
399 // the lowest-index audio stream. 399 // the lowest-index audio stream.
400 pending_seek_ = true; 400 pending_seek_ = true;
401 base::PostTaskAndReplyWithResult( 401 base::PostTaskAndReplyWithResult(
402 blocking_thread_.message_loop_proxy().get(), 402 blocking_thread_.message_loop_proxy().get(),
403 FROM_HERE, 403 FROM_HERE,
404 base::Bind(&av_seek_frame, 404 base::Bind(&av_seek_frame,
405 glue_->format_context(), 405 glue_->format_context(),
406 -1, 406 -1,
407 time.InMicroseconds(), 407 time.InMicroseconds(),
408 flags), 408 flags),
409 base::Bind(&FFmpegDemuxer::OnSeekFrameDone, weak_this_, cb)); 409 base::Bind(&FFmpegDemuxer::OnSeekFrameDone, weak_this_, cb));
410 } 410 }
411 411
412 void FFmpegDemuxer::OnAudioRendererDisabled() { 412 void FFmpegDemuxer::OnAudioRendererDisabled() {
413 DCHECK(message_loop_->BelongsToCurrentThread()); 413 DCHECK(task_runner_->BelongsToCurrentThread());
414 audio_disabled_ = true; 414 audio_disabled_ = true;
415 StreamVector::iterator iter; 415 StreamVector::iterator iter;
416 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { 416 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
417 if (*iter && (*iter)->type() == DemuxerStream::AUDIO) { 417 if (*iter && (*iter)->type() == DemuxerStream::AUDIO) {
418 (*iter)->Stop(); 418 (*iter)->Stop();
419 } 419 }
420 } 420 }
421 } 421 }
422 422
423 void FFmpegDemuxer::Initialize(DemuxerHost* host, 423 void FFmpegDemuxer::Initialize(DemuxerHost* host,
424 const PipelineStatusCB& status_cb, 424 const PipelineStatusCB& status_cb,
425 bool enable_text_tracks) { 425 bool enable_text_tracks) {
426 DCHECK(message_loop_->BelongsToCurrentThread()); 426 DCHECK(task_runner_->BelongsToCurrentThread());
427 host_ = host; 427 host_ = host;
428 weak_this_ = weak_factory_.GetWeakPtr(); 428 weak_this_ = weak_factory_.GetWeakPtr();
429 text_enabled_ = enable_text_tracks; 429 text_enabled_ = enable_text_tracks;
430 430
431 // TODO(scherkus): DataSource should have a host by this point, 431 // TODO(scherkus): DataSource should have a host by this point,
432 // see http://crbug.com/122071 432 // see http://crbug.com/122071
433 data_source_->set_host(host); 433 data_source_->set_host(host);
434 434
435 glue_.reset(new FFmpegGlue(&url_protocol_)); 435 glue_.reset(new FFmpegGlue(&url_protocol_));
436 AVFormatContext* format_context = glue_->format_context(); 436 AVFormatContext* format_context = glue_->format_context();
437 437
438 // Disable ID3v1 tag reading to avoid costly seeks to end of file for data we 438 // Disable ID3v1 tag reading to avoid costly seeks to end of file for data we
439 // don't use. FFmpeg will only read ID3v1 tags if no other metadata is 439 // don't use. FFmpeg will only read ID3v1 tags if no other metadata is
440 // available, so add a metadata entry to ensure some is always present. 440 // available, so add a metadata entry to ensure some is always present.
441 av_dict_set(&format_context->metadata, "skip_id3v1_tags", "", 0); 441 av_dict_set(&format_context->metadata, "skip_id3v1_tags", "", 0);
442 442
443 // Open the AVFormatContext using our glue layer. 443 // Open the AVFormatContext using our glue layer.
444 CHECK(blocking_thread_.Start()); 444 CHECK(blocking_thread_.Start());
445 base::PostTaskAndReplyWithResult( 445 base::PostTaskAndReplyWithResult(
446 blocking_thread_.message_loop_proxy().get(), 446 blocking_thread_.message_loop_proxy().get(),
447 FROM_HERE, 447 FROM_HERE,
448 base::Bind(&FFmpegGlue::OpenContext, base::Unretained(glue_.get())), 448 base::Bind(&FFmpegGlue::OpenContext, base::Unretained(glue_.get())),
449 base::Bind(&FFmpegDemuxer::OnOpenContextDone, weak_this_, status_cb)); 449 base::Bind(&FFmpegDemuxer::OnOpenContextDone, weak_this_, status_cb));
450 } 450 }
451 451
452 DemuxerStream* FFmpegDemuxer::GetStream(DemuxerStream::Type type) { 452 DemuxerStream* FFmpegDemuxer::GetStream(DemuxerStream::Type type) {
453 DCHECK(message_loop_->BelongsToCurrentThread()); 453 DCHECK(task_runner_->BelongsToCurrentThread());
454 return GetFFmpegStream(type); 454 return GetFFmpegStream(type);
455 } 455 }
456 456
457 FFmpegDemuxerStream* FFmpegDemuxer::GetFFmpegStream( 457 FFmpegDemuxerStream* FFmpegDemuxer::GetFFmpegStream(
458 DemuxerStream::Type type) const { 458 DemuxerStream::Type type) const {
459 StreamVector::const_iterator iter; 459 StreamVector::const_iterator iter;
460 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { 460 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
461 if (*iter && (*iter)->type() == type) { 461 if (*iter && (*iter)->type() == type) {
462 return *iter; 462 return *iter;
463 } 463 }
464 } 464 }
465 return NULL; 465 return NULL;
466 } 466 }
467 467
468 base::TimeDelta FFmpegDemuxer::GetStartTime() const { 468 base::TimeDelta FFmpegDemuxer::GetStartTime() const {
469 DCHECK(message_loop_->BelongsToCurrentThread()); 469 DCHECK(task_runner_->BelongsToCurrentThread());
470 return start_time_; 470 return start_time_;
471 } 471 }
472 472
473 void FFmpegDemuxer::AddTextStreams() { 473 void FFmpegDemuxer::AddTextStreams() {
474 DCHECK(message_loop_->BelongsToCurrentThread()); 474 DCHECK(task_runner_->BelongsToCurrentThread());
475 475
476 for (StreamVector::size_type idx = 0; idx < streams_.size(); ++idx) { 476 for (StreamVector::size_type idx = 0; idx < streams_.size(); ++idx) {
477 FFmpegDemuxerStream* stream = streams_[idx]; 477 FFmpegDemuxerStream* stream = streams_[idx];
478 if (stream == NULL || stream->type() != DemuxerStream::TEXT) 478 if (stream == NULL || stream->type() != DemuxerStream::TEXT)
479 continue; 479 continue;
480 480
481 TextKind kind = stream->GetTextKind(); 481 TextKind kind = stream->GetTextKind();
482 std::string title = stream->GetMetadata("title"); 482 std::string title = stream->GetMetadata("title");
483 std::string language = stream->GetMetadata("language"); 483 std::string language = stream->GetMetadata("language");
484 484
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
520 520
521 // Do math in floating point as we'd overflow an int64 if the filesize was 521 // Do math in floating point as we'd overflow an int64 if the filesize was
522 // larger than ~1073GB. 522 // larger than ~1073GB.
523 double bytes = filesize_in_bytes; 523 double bytes = filesize_in_bytes;
524 double duration_us = duration.InMicroseconds(); 524 double duration_us = duration.InMicroseconds();
525 return bytes * 8000000.0 / duration_us; 525 return bytes * 8000000.0 / duration_us;
526 } 526 }
527 527
528 void FFmpegDemuxer::OnOpenContextDone(const PipelineStatusCB& status_cb, 528 void FFmpegDemuxer::OnOpenContextDone(const PipelineStatusCB& status_cb,
529 bool result) { 529 bool result) {
530 DCHECK(message_loop_->BelongsToCurrentThread()); 530 DCHECK(task_runner_->BelongsToCurrentThread());
531 if (!blocking_thread_.IsRunning()) { 531 if (!blocking_thread_.IsRunning()) {
532 status_cb.Run(PIPELINE_ERROR_ABORT); 532 status_cb.Run(PIPELINE_ERROR_ABORT);
533 return; 533 return;
534 } 534 }
535 535
536 if (!result) { 536 if (!result) {
537 status_cb.Run(DEMUXER_ERROR_COULD_NOT_OPEN); 537 status_cb.Run(DEMUXER_ERROR_COULD_NOT_OPEN);
538 return; 538 return;
539 } 539 }
540 540
541 // Fully initialize AVFormatContext by parsing the stream a little. 541 // Fully initialize AVFormatContext by parsing the stream a little.
542 base::PostTaskAndReplyWithResult( 542 base::PostTaskAndReplyWithResult(
543 blocking_thread_.message_loop_proxy().get(), 543 blocking_thread_.message_loop_proxy().get(),
544 FROM_HERE, 544 FROM_HERE,
545 base::Bind(&avformat_find_stream_info, 545 base::Bind(&avformat_find_stream_info,
546 glue_->format_context(), 546 glue_->format_context(),
547 static_cast<AVDictionary**>(NULL)), 547 static_cast<AVDictionary**>(NULL)),
548 base::Bind(&FFmpegDemuxer::OnFindStreamInfoDone, weak_this_, status_cb)); 548 base::Bind(&FFmpegDemuxer::OnFindStreamInfoDone, weak_this_, status_cb));
549 } 549 }
550 550
551 void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb, 551 void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb,
552 int result) { 552 int result) {
553 DCHECK(message_loop_->BelongsToCurrentThread()); 553 DCHECK(task_runner_->BelongsToCurrentThread());
554 if (!blocking_thread_.IsRunning() || !data_source_) { 554 if (!blocking_thread_.IsRunning() || !data_source_) {
555 status_cb.Run(PIPELINE_ERROR_ABORT); 555 status_cb.Run(PIPELINE_ERROR_ABORT);
556 return; 556 return;
557 } 557 }
558 558
559 if (result < 0) { 559 if (result < 0) {
560 status_cb.Run(DEMUXER_ERROR_COULD_NOT_PARSE); 560 status_cb.Run(DEMUXER_ERROR_COULD_NOT_PARSE);
561 return; 561 return;
562 } 562 }
563 563
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
721 721
722 722
723 media_log_->SetDoubleProperty("max_duration", max_duration.InSecondsF()); 723 media_log_->SetDoubleProperty("max_duration", max_duration.InSecondsF());
724 media_log_->SetDoubleProperty("start_time", start_time_.InSecondsF()); 724 media_log_->SetDoubleProperty("start_time", start_time_.InSecondsF());
725 media_log_->SetIntegerProperty("bitrate", bitrate_); 725 media_log_->SetIntegerProperty("bitrate", bitrate_);
726 726
727 status_cb.Run(PIPELINE_OK); 727 status_cb.Run(PIPELINE_OK);
728 } 728 }
729 729
730 void FFmpegDemuxer::OnSeekFrameDone(const PipelineStatusCB& cb, int result) { 730 void FFmpegDemuxer::OnSeekFrameDone(const PipelineStatusCB& cb, int result) {
731 DCHECK(message_loop_->BelongsToCurrentThread()); 731 DCHECK(task_runner_->BelongsToCurrentThread());
732 CHECK(pending_seek_); 732 CHECK(pending_seek_);
733 pending_seek_ = false; 733 pending_seek_ = false;
734 734
735 if (!blocking_thread_.IsRunning()) { 735 if (!blocking_thread_.IsRunning()) {
736 cb.Run(PIPELINE_ERROR_ABORT); 736 cb.Run(PIPELINE_ERROR_ABORT);
737 return; 737 return;
738 } 738 }
739 739
740 if (result < 0) { 740 if (result < 0) {
741 // Use VLOG(1) instead of NOTIMPLEMENTED() to prevent the message being 741 // Use VLOG(1) instead of NOTIMPLEMENTED() to prevent the message being
(...skipping 10 matching lines...) Expand all
752 } 752 }
753 753
754 // Resume reading until capacity. 754 // Resume reading until capacity.
755 ReadFrameIfNeeded(); 755 ReadFrameIfNeeded();
756 756
757 // Notify we're finished seeking. 757 // Notify we're finished seeking.
758 cb.Run(PIPELINE_OK); 758 cb.Run(PIPELINE_OK);
759 } 759 }
760 760
761 void FFmpegDemuxer::ReadFrameIfNeeded() { 761 void FFmpegDemuxer::ReadFrameIfNeeded() {
762 DCHECK(message_loop_->BelongsToCurrentThread()); 762 DCHECK(task_runner_->BelongsToCurrentThread());
763 763
764 // Make sure we have work to do before reading. 764 // Make sure we have work to do before reading.
765 if (!blocking_thread_.IsRunning() || !StreamsHaveAvailableCapacity() || 765 if (!blocking_thread_.IsRunning() || !StreamsHaveAvailableCapacity() ||
766 pending_read_ || pending_seek_) { 766 pending_read_ || pending_seek_) {
767 return; 767 return;
768 } 768 }
769 769
770 // Allocate and read an AVPacket from the media. Save |packet_ptr| since 770 // Allocate and read an AVPacket from the media. Save |packet_ptr| since
771 // evaluation order of packet.get() and base::Passed(&packet) is 771 // evaluation order of packet.get() and base::Passed(&packet) is
772 // undefined. 772 // undefined.
773 ScopedAVPacket packet(new AVPacket()); 773 ScopedAVPacket packet(new AVPacket());
774 AVPacket* packet_ptr = packet.get(); 774 AVPacket* packet_ptr = packet.get();
775 775
776 pending_read_ = true; 776 pending_read_ = true;
777 base::PostTaskAndReplyWithResult( 777 base::PostTaskAndReplyWithResult(
778 blocking_thread_.message_loop_proxy().get(), 778 blocking_thread_.message_loop_proxy().get(),
779 FROM_HERE, 779 FROM_HERE,
780 base::Bind(&av_read_frame, glue_->format_context(), packet_ptr), 780 base::Bind(&av_read_frame, glue_->format_context(), packet_ptr),
781 base::Bind( 781 base::Bind(
782 &FFmpegDemuxer::OnReadFrameDone, weak_this_, base::Passed(&packet))); 782 &FFmpegDemuxer::OnReadFrameDone, weak_this_, base::Passed(&packet)));
783 } 783 }
784 784
785 void FFmpegDemuxer::OnReadFrameDone(ScopedAVPacket packet, int result) { 785 void FFmpegDemuxer::OnReadFrameDone(ScopedAVPacket packet, int result) {
786 DCHECK(message_loop_->BelongsToCurrentThread()); 786 DCHECK(task_runner_->BelongsToCurrentThread());
787 DCHECK(pending_read_); 787 DCHECK(pending_read_);
788 pending_read_ = false; 788 pending_read_ = false;
789 789
790 if (!blocking_thread_.IsRunning() || pending_seek_) { 790 if (!blocking_thread_.IsRunning() || pending_seek_) {
791 return; 791 return;
792 } 792 }
793 793
794 if (result < 0) { 794 if (result < 0) {
795 // Update the duration based on the audio stream if 795 // Update the duration based on the audio stream if
796 // it was previously unknown http://crbug.com/86830 796 // it was previously unknown http://crbug.com/86830
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
864 864
865 // Keep reading until we've reached capacity. 865 // Keep reading until we've reached capacity.
866 ReadFrameIfNeeded(); 866 ReadFrameIfNeeded();
867 } 867 }
868 868
869 void FFmpegDemuxer::OnDataSourceStopped(const base::Closure& callback) { 869 void FFmpegDemuxer::OnDataSourceStopped(const base::Closure& callback) {
870 // This will block until all tasks complete. Note that after this returns it's 870 // This will block until all tasks complete. Note that after this returns it's
871 // possible for reply tasks (e.g., OnReadFrameDone()) to be queued on this 871 // possible for reply tasks (e.g., OnReadFrameDone()) to be queued on this
872 // thread. Each of the reply task methods must check whether we've stopped the 872 // thread. Each of the reply task methods must check whether we've stopped the
873 // thread and drop their results on the floor. 873 // thread and drop their results on the floor.
874 DCHECK(message_loop_->BelongsToCurrentThread()); 874 DCHECK(task_runner_->BelongsToCurrentThread());
875 blocking_thread_.Stop(); 875 blocking_thread_.Stop();
876 876
877 StreamVector::iterator iter; 877 StreamVector::iterator iter;
878 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { 878 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
879 if (*iter) 879 if (*iter)
880 (*iter)->Stop(); 880 (*iter)->Stop();
881 } 881 }
882 882
883 callback.Run(); 883 callback.Run();
884 } 884 }
885 885
886 bool FFmpegDemuxer::StreamsHaveAvailableCapacity() { 886 bool FFmpegDemuxer::StreamsHaveAvailableCapacity() {
887 DCHECK(message_loop_->BelongsToCurrentThread()); 887 DCHECK(task_runner_->BelongsToCurrentThread());
888 StreamVector::iterator iter; 888 StreamVector::iterator iter;
889 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { 889 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
890 if (*iter && (*iter)->HasAvailableCapacity()) { 890 if (*iter && (*iter)->HasAvailableCapacity()) {
891 return true; 891 return true;
892 } 892 }
893 } 893 }
894 return false; 894 return false;
895 } 895 }
896 896
897 void FFmpegDemuxer::StreamHasEnded() { 897 void FFmpegDemuxer::StreamHasEnded() {
898 DCHECK(message_loop_->BelongsToCurrentThread()); 898 DCHECK(task_runner_->BelongsToCurrentThread());
899 StreamVector::iterator iter; 899 StreamVector::iterator iter;
900 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { 900 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
901 if (!*iter || 901 if (!*iter ||
902 (audio_disabled_ && (*iter)->type() == DemuxerStream::AUDIO)) { 902 (audio_disabled_ && (*iter)->type() == DemuxerStream::AUDIO)) {
903 continue; 903 continue;
904 } 904 }
905 (*iter)->SetEndOfStream(); 905 (*iter)->SetEndOfStream();
906 } 906 }
907 } 907 }
908 908
909 void FFmpegDemuxer::FireNeedKey(const std::string& init_data_type, 909 void FFmpegDemuxer::FireNeedKey(const std::string& init_data_type,
910 const std::string& encryption_key_id) { 910 const std::string& encryption_key_id) {
911 std::vector<uint8> key_id_local(encryption_key_id.begin(), 911 std::vector<uint8> key_id_local(encryption_key_id.begin(),
912 encryption_key_id.end()); 912 encryption_key_id.end());
913 need_key_cb_.Run(init_data_type, key_id_local); 913 need_key_cb_.Run(init_data_type, key_id_local);
914 } 914 }
915 915
916 void FFmpegDemuxer::NotifyCapacityAvailable() { 916 void FFmpegDemuxer::NotifyCapacityAvailable() {
917 DCHECK(message_loop_->BelongsToCurrentThread()); 917 DCHECK(task_runner_->BelongsToCurrentThread());
918 ReadFrameIfNeeded(); 918 ReadFrameIfNeeded();
919 } 919 }
920 920
921 void FFmpegDemuxer::NotifyBufferingChanged() { 921 void FFmpegDemuxer::NotifyBufferingChanged() {
922 DCHECK(message_loop_->BelongsToCurrentThread()); 922 DCHECK(task_runner_->BelongsToCurrentThread());
923 Ranges<base::TimeDelta> buffered; 923 Ranges<base::TimeDelta> buffered;
924 FFmpegDemuxerStream* audio = 924 FFmpegDemuxerStream* audio =
925 audio_disabled_ ? NULL : GetFFmpegStream(DemuxerStream::AUDIO); 925 audio_disabled_ ? NULL : GetFFmpegStream(DemuxerStream::AUDIO);
926 FFmpegDemuxerStream* video = GetFFmpegStream(DemuxerStream::VIDEO); 926 FFmpegDemuxerStream* video = GetFFmpegStream(DemuxerStream::VIDEO);
927 if (audio && video) { 927 if (audio && video) {
928 buffered = audio->GetBufferedRanges().IntersectionWith( 928 buffered = audio->GetBufferedRanges().IntersectionWith(
929 video->GetBufferedRanges()); 929 video->GetBufferedRanges());
930 } else if (audio) { 930 } else if (audio) {
931 buffered = audio->GetBufferedRanges(); 931 buffered = audio->GetBufferedRanges();
932 } else if (video) { 932 } else if (video) {
933 buffered = video->GetBufferedRanges(); 933 buffered = video->GetBufferedRanges();
934 } 934 }
935 for (size_t i = 0; i < buffered.size(); ++i) 935 for (size_t i = 0; i < buffered.size(); ++i)
936 host_->AddBufferedTimeRange(buffered.start(i), buffered.end(i)); 936 host_->AddBufferedTimeRange(buffered.start(i), buffered.end(i));
937 } 937 }
938 938
939 void FFmpegDemuxer::OnDataSourceError() { 939 void FFmpegDemuxer::OnDataSourceError() {
940 host_->OnDemuxerError(PIPELINE_ERROR_READ); 940 host_->OnDemuxerError(PIPELINE_ERROR_READ);
941 } 941 }
942 942
943 } // namespace media 943 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/ffmpeg_demuxer.h ('k') | media/filters/ffmpeg_video_decoder.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698