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

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

Issue 6648004: DemuxerFactory is born! (Closed)
Patch Set: Responses to scherkus@ CR Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/filters/ffmpeg_demuxer.h ('k') | media/filters/ffmpeg_demuxer_factory.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) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 "base/callback.h" 5 #include "base/callback.h"
6 #include "base/command_line.h" 6 #include "base/command_line.h"
7 #include "base/message_loop.h" 7 #include "base/message_loop.h"
8 #include "base/scoped_ptr.h" 8 #include "base/scoped_ptr.h"
9 #include "base/stl_util-inl.h" 9 #include "base/stl_util-inl.h"
10 #include "base/string_util.h" 10 #include "base/string_util.h"
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after
245 245
246 // 246 //
247 // FFmpegDemuxer 247 // FFmpegDemuxer
248 // 248 //
249 FFmpegDemuxer::FFmpegDemuxer(MessageLoop* message_loop) 249 FFmpegDemuxer::FFmpegDemuxer(MessageLoop* message_loop)
250 : message_loop_(message_loop), 250 : message_loop_(message_loop),
251 format_context_(NULL), 251 format_context_(NULL),
252 read_event_(false, false), 252 read_event_(false, false),
253 read_has_failed_(false), 253 read_has_failed_(false),
254 last_read_bytes_(0), 254 last_read_bytes_(0),
255 read_position_(0) { 255 read_position_(0),
256 max_duration_(base::TimeDelta::FromMicroseconds(-1)),
257 deferred_status_(PIPELINE_OK) {
256 DCHECK(message_loop_); 258 DCHECK(message_loop_);
257 } 259 }
258 260
259 FFmpegDemuxer::~FFmpegDemuxer() { 261 FFmpegDemuxer::~FFmpegDemuxer() {
260 // In this destructor, we clean up resources held by FFmpeg. It is ugly to 262 // In this destructor, we clean up resources held by FFmpeg. It is ugly to
261 // close the codec contexts here because the corresponding codecs are opened 263 // close the codec contexts here because the corresponding codecs are opened
262 // in the decoder filters. By reaching this point, all filters should have 264 // in the decoder filters. By reaching this point, all filters should have
263 // stopped, so this is the only safe place to do the global clean up. 265 // stopped, so this is the only safe place to do the global clean up.
264 // TODO(hclam): close the codecs in the corresponding decoders. 266 // TODO(hclam): close the codecs in the corresponding decoders.
265 if (!format_context_) 267 if (!format_context_)
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
308 // asynchronous, should change how seek works to make it fully asynchronous. 310 // asynchronous, should change how seek works to make it fully asynchronous.
309 message_loop_->PostTask(FROM_HERE, 311 message_loop_->PostTask(FROM_HERE,
310 NewRunnableMethod(this, &FFmpegDemuxer::SeekTask, time, callback)); 312 NewRunnableMethod(this, &FFmpegDemuxer::SeekTask, time, callback));
311 } 313 }
312 314
313 void FFmpegDemuxer::OnAudioRendererDisabled() { 315 void FFmpegDemuxer::OnAudioRendererDisabled() {
314 message_loop_->PostTask(FROM_HERE, 316 message_loop_->PostTask(FROM_HERE,
315 NewRunnableMethod(this, &FFmpegDemuxer::DisableAudioStreamTask)); 317 NewRunnableMethod(this, &FFmpegDemuxer::DisableAudioStreamTask));
316 } 318 }
317 319
320 void FFmpegDemuxer::set_host(FilterHost* filter_host) {
321 Demuxer::set_host(filter_host);
322 if (data_source_)
323 data_source_->set_host(filter_host);
324 if (max_duration_.InMicroseconds() >= 0)
325 host()->SetDuration(max_duration_);
326 if (read_position_ > 0)
327 host()->SetCurrentReadPosition(read_position_);
328 if (deferred_status_ != PIPELINE_OK)
329 host()->SetError(deferred_status_);
330 }
331
318 void FFmpegDemuxer::Initialize(DataSource* data_source, 332 void FFmpegDemuxer::Initialize(DataSource* data_source,
319 FilterCallback* callback) { 333 PipelineStatusCallback* callback) {
320 message_loop_->PostTask( 334 message_loop_->PostTask(
321 FROM_HERE, 335 FROM_HERE,
322 NewRunnableMethod(this, 336 NewRunnableMethod(this,
323 &FFmpegDemuxer::InitializeTask, 337 &FFmpegDemuxer::InitializeTask,
324 make_scoped_refptr(data_source), 338 make_scoped_refptr(data_source),
325 callback)); 339 callback));
326 } 340 }
327 341
328 size_t FFmpegDemuxer::GetNumberOfStreams() { 342 size_t FFmpegDemuxer::GetNumberOfStreams() {
329 return streams_.size(); 343 return streams_.size();
(...skipping 21 matching lines...) Expand all
351 365
352 // Asynchronous read from data source. 366 // Asynchronous read from data source.
353 data_source_->Read(read_position_, size, data, 367 data_source_->Read(read_position_, size, data,
354 NewCallback(this, &FFmpegDemuxer::OnReadCompleted)); 368 NewCallback(this, &FFmpegDemuxer::OnReadCompleted));
355 369
356 // TODO(hclam): The method is called on the demuxer thread and this method 370 // TODO(hclam): The method is called on the demuxer thread and this method
357 // call will block the thread. We need to implemented an additional thread to 371 // call will block the thread. We need to implemented an additional thread to
358 // let FFmpeg demuxer methods to run on. 372 // let FFmpeg demuxer methods to run on.
359 size_t last_read_bytes = WaitForRead(); 373 size_t last_read_bytes = WaitForRead();
360 if (last_read_bytes == DataSource::kReadError) { 374 if (last_read_bytes == DataSource::kReadError) {
361 host()->SetError(PIPELINE_ERROR_READ); 375 if (host())
376 host()->SetError(PIPELINE_ERROR_READ);
377 else
378 deferred_status_ = PIPELINE_ERROR_READ;
362 379
363 // Returns with a negative number to signal an error to FFmpeg. 380 // Returns with a negative number to signal an error to FFmpeg.
364 read_has_failed_ = true; 381 read_has_failed_ = true;
365 return AVERROR_IO; 382 return AVERROR_IO;
366 } 383 }
367 read_position_ += last_read_bytes; 384 read_position_ += last_read_bytes;
368 385
369 host()->SetCurrentReadPosition(read_position_); 386 if (host())
387 host()->SetCurrentReadPosition(read_position_);
370 388
371 return last_read_bytes; 389 return last_read_bytes;
372 } 390 }
373 391
374 bool FFmpegDemuxer::GetPosition(int64* position_out) { 392 bool FFmpegDemuxer::GetPosition(int64* position_out) {
375 *position_out = read_position_; 393 *position_out = read_position_;
376 return true; 394 return true;
377 } 395 }
378 396
379 bool FFmpegDemuxer::SetPosition(int64 position) { 397 bool FFmpegDemuxer::SetPosition(int64 position) {
(...skipping 18 matching lines...) Expand all
398 DCHECK(data_source_); 416 DCHECK(data_source_);
399 417
400 return data_source_->IsStreaming(); 418 return data_source_->IsStreaming();
401 } 419 }
402 420
403 MessageLoop* FFmpegDemuxer::message_loop() { 421 MessageLoop* FFmpegDemuxer::message_loop() {
404 return message_loop_; 422 return message_loop_;
405 } 423 }
406 424
407 void FFmpegDemuxer::InitializeTask(DataSource* data_source, 425 void FFmpegDemuxer::InitializeTask(DataSource* data_source,
408 FilterCallback* callback) { 426 PipelineStatusCallback* callback) {
409 DCHECK_EQ(MessageLoop::current(), message_loop_); 427 DCHECK_EQ(MessageLoop::current(), message_loop_);
410 scoped_ptr<FilterCallback> c(callback); 428 scoped_ptr<PipelineStatusCallback> callback_deleter(callback);
411 429
412 data_source_ = data_source; 430 data_source_ = data_source;
431 if (host())
432 data_source_->set_host(host());
413 433
414 // Add ourself to Protocol list and get our unique key. 434 // Add ourself to Protocol list and get our unique key.
415 std::string key = FFmpegGlue::GetInstance()->AddProtocol(this); 435 std::string key = FFmpegGlue::GetInstance()->AddProtocol(this);
416 436
417 // Open FFmpeg AVFormatContext. 437 // Open FFmpeg AVFormatContext.
418 DCHECK(!format_context_); 438 DCHECK(!format_context_);
419 AVFormatContext* context = NULL; 439 AVFormatContext* context = NULL;
420 int result = av_open_input_file(&context, key.c_str(), NULL, 0, NULL); 440 int result = av_open_input_file(&context, key.c_str(), NULL, 0, NULL);
421 441
422 // Remove ourself from protocol list. 442 // Remove ourself from protocol list.
423 FFmpegGlue::GetInstance()->RemoveProtocol(this); 443 FFmpegGlue::GetInstance()->RemoveProtocol(this);
424 444
425 if (result < 0) { 445 if (result < 0) {
426 host()->SetError(DEMUXER_ERROR_COULD_NOT_OPEN); 446 callback->Run(DEMUXER_ERROR_COULD_NOT_OPEN);
427 callback->Run();
428 return; 447 return;
429 } 448 }
430 449
431 DCHECK(context); 450 DCHECK(context);
432 format_context_ = context; 451 format_context_ = context;
433 452
434 // Fully initialize AVFormatContext by parsing the stream a little. 453 // Fully initialize AVFormatContext by parsing the stream a little.
435 result = av_find_stream_info(format_context_); 454 result = av_find_stream_info(format_context_);
436 if (result < 0) { 455 if (result < 0) {
437 host()->SetError(DEMUXER_ERROR_COULD_NOT_PARSE); 456 callback->Run(DEMUXER_ERROR_COULD_NOT_PARSE);
438 callback->Run();
439 return; 457 return;
440 } 458 }
441 459
442 // Create demuxer streams for all supported streams. 460 // Create demuxer streams for all supported streams.
443 base::TimeDelta max_duration; 461 base::TimeDelta max_duration;
444 const bool kDemuxerIsWebm = !strcmp("webm", format_context_->iformat->name); 462 const bool kDemuxerIsWebm = !strcmp("webm", format_context_->iformat->name);
445 for (size_t i = 0; i < format_context_->nb_streams; ++i) { 463 for (size_t i = 0; i < format_context_->nb_streams; ++i) {
446 AVCodecContext* codec_context = format_context_->streams[i]->codec; 464 AVCodecContext* codec_context = format_context_->streams[i]->codec;
447 CodecType codec_type = codec_context->codec_type; 465 CodecType codec_type = codec_context->codec_type;
448 if (codec_type == CODEC_TYPE_AUDIO || codec_type == CODEC_TYPE_VIDEO) { 466 if (codec_type == CODEC_TYPE_AUDIO || codec_type == CODEC_TYPE_VIDEO) {
(...skipping 10 matching lines...) Expand all
459 477
460 DCHECK(demuxer_stream); 478 DCHECK(demuxer_stream);
461 streams_.push_back(make_scoped_refptr(demuxer_stream)); 479 streams_.push_back(make_scoped_refptr(demuxer_stream));
462 packet_streams_.push_back(make_scoped_refptr(demuxer_stream)); 480 packet_streams_.push_back(make_scoped_refptr(demuxer_stream));
463 max_duration = std::max(max_duration, demuxer_stream->duration()); 481 max_duration = std::max(max_duration, demuxer_stream->duration());
464 } else { 482 } else {
465 packet_streams_.push_back(NULL); 483 packet_streams_.push_back(NULL);
466 } 484 }
467 } 485 }
468 if (streams_.empty()) { 486 if (streams_.empty()) {
469 host()->SetError(DEMUXER_ERROR_NO_SUPPORTED_STREAMS); 487 callback->Run(DEMUXER_ERROR_NO_SUPPORTED_STREAMS);
470 callback->Run();
471 return; 488 return;
472 } 489 }
473 if (format_context_->duration != static_cast<int64_t>(AV_NOPTS_VALUE)) { 490 if (format_context_->duration != static_cast<int64_t>(AV_NOPTS_VALUE)) {
474 // If there is a duration value in the container use that to find the 491 // If there is a duration value in the container use that to find the
475 // maximum between it and the duration from A/V streams. 492 // maximum between it and the duration from A/V streams.
476 const AVRational av_time_base = {1, AV_TIME_BASE}; 493 const AVRational av_time_base = {1, AV_TIME_BASE};
477 max_duration = 494 max_duration =
478 std::max(max_duration, 495 std::max(max_duration,
479 ConvertTimestamp(av_time_base, format_context_->duration)); 496 ConvertTimestamp(av_time_base, format_context_->duration));
480 } else { 497 } else {
481 // If the duration is not a valid value. Assume that this is a live stream 498 // If the duration is not a valid value. Assume that this is a live stream
482 // and we set duration to the maximum int64 number to represent infinity. 499 // and we set duration to the maximum int64 number to represent infinity.
483 max_duration = base::TimeDelta::FromMicroseconds( 500 max_duration = base::TimeDelta::FromMicroseconds(
484 Limits::kMaxTimeInMicroseconds); 501 Limits::kMaxTimeInMicroseconds);
485 } 502 }
486 503
487 // Good to go: set the duration and notify we're done initializing. 504 // Good to go: set the duration and notify we're done initializing.
488 host()->SetDuration(max_duration); 505 if (host())
489 callback->Run(); 506 host()->SetDuration(max_duration);
507 max_duration_ = max_duration;
508 callback->Run(PIPELINE_OK);
490 } 509 }
491 510
492 void FFmpegDemuxer::SeekTask(base::TimeDelta time, FilterCallback* callback) { 511 void FFmpegDemuxer::SeekTask(base::TimeDelta time, FilterCallback* callback) {
493 DCHECK_EQ(MessageLoop::current(), message_loop_); 512 DCHECK_EQ(MessageLoop::current(), message_loop_);
494 scoped_ptr<FilterCallback> c(callback); 513 scoped_ptr<FilterCallback> c(callback);
495 514
496 // Tell streams to flush buffers due to seeking. 515 // Tell streams to flush buffers due to seeking.
497 StreamVector::iterator iter; 516 StreamVector::iterator iter;
498 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { 517 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
499 (*iter)->FlushBuffers(); 518 (*iter)->FlushBuffers();
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
567 PostDemuxTask(); 586 PostDemuxTask();
568 } 587 }
569 } 588 }
570 589
571 void FFmpegDemuxer::StopTask(FilterCallback* callback) { 590 void FFmpegDemuxer::StopTask(FilterCallback* callback) {
572 DCHECK_EQ(MessageLoop::current(), message_loop_); 591 DCHECK_EQ(MessageLoop::current(), message_loop_);
573 StreamVector::iterator iter; 592 StreamVector::iterator iter;
574 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { 593 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
575 (*iter)->Stop(); 594 (*iter)->Stop();
576 } 595 }
577 if (callback) { 596 if (data_source_) {
597 data_source_->Stop(callback);
598 } else {
578 callback->Run(); 599 callback->Run();
579 delete callback; 600 delete callback;
580 } 601 }
581 } 602 }
582 603
583 void FFmpegDemuxer::DisableAudioStreamTask() { 604 void FFmpegDemuxer::DisableAudioStreamTask() {
584 DCHECK_EQ(MessageLoop::current(), message_loop_); 605 DCHECK_EQ(MessageLoop::current(), message_loop_);
585 606
586 StreamVector::iterator iter; 607 StreamVector::iterator iter;
587 for (size_t i = 0; i < packet_streams_.size(); ++i) { 608 for (size_t i = 0; i < packet_streams_.size(); ++i) {
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
627 read_event_.Wait(); 648 read_event_.Wait();
628 return last_read_bytes_; 649 return last_read_bytes_;
629 } 650 }
630 651
631 void FFmpegDemuxer::SignalReadCompleted(size_t size) { 652 void FFmpegDemuxer::SignalReadCompleted(size_t size) {
632 last_read_bytes_ = size; 653 last_read_bytes_ = size;
633 read_event_.Signal(); 654 read_event_.Signal();
634 } 655 }
635 656
636 } // namespace media 657 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/ffmpeg_demuxer.h ('k') | media/filters/ffmpeg_demuxer_factory.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698