| 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 "base/bind.h" | 5 #include "base/bind.h" |
| 6 #include "base/callback.h" | 6 #include "base/callback.h" |
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "base/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
| 9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
| 10 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
| (...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 269 const AVRational& time_base, int64 timestamp) { | 269 const AVRational& time_base, int64 timestamp) { |
| 270 if (timestamp == static_cast<int64>(AV_NOPTS_VALUE)) | 270 if (timestamp == static_cast<int64>(AV_NOPTS_VALUE)) |
| 271 return kNoTimestamp(); | 271 return kNoTimestamp(); |
| 272 | 272 |
| 273 return ConvertFromTimeBase(time_base, timestamp); | 273 return ConvertFromTimeBase(time_base, timestamp); |
| 274 } | 274 } |
| 275 | 275 |
| 276 // | 276 // |
| 277 // FFmpegDemuxer | 277 // FFmpegDemuxer |
| 278 // | 278 // |
| 279 FFmpegDemuxer::FFmpegDemuxer(MessageLoop* message_loop, bool local_source) | 279 FFmpegDemuxer::FFmpegDemuxer( |
| 280 MessageLoop* message_loop, |
| 281 const scoped_refptr<DataSource>& data_source, |
| 282 bool local_source) |
| 280 : message_loop_(message_loop), | 283 : message_loop_(message_loop), |
| 281 local_source_(local_source), | 284 local_source_(local_source), |
| 282 format_context_(NULL), | 285 format_context_(NULL), |
| 286 data_source_(data_source), |
| 283 read_event_(false, false), | 287 read_event_(false, false), |
| 284 read_has_failed_(false), | 288 read_has_failed_(false), |
| 285 last_read_bytes_(0), | 289 last_read_bytes_(0), |
| 286 read_position_(0), | 290 read_position_(0), |
| 287 max_duration_(base::TimeDelta::FromMicroseconds(-1)), | 291 bitrate_(0), |
| 288 deferred_status_(PIPELINE_OK), | |
| 289 first_seek_hack_(true), | 292 first_seek_hack_(true), |
| 290 start_time_(kNoTimestamp()), | 293 start_time_(kNoTimestamp()), |
| 291 audio_disabled_(false) { | 294 audio_disabled_(false) { |
| 292 DCHECK(message_loop_); | 295 DCHECK(message_loop_); |
| 296 DCHECK(data_source_); |
| 293 } | 297 } |
| 294 | 298 |
| 295 FFmpegDemuxer::~FFmpegDemuxer() { | 299 FFmpegDemuxer::~FFmpegDemuxer() { |
| 296 // In this destructor, we clean up resources held by FFmpeg. It is ugly to | 300 // In this destructor, we clean up resources held by FFmpeg. It is ugly to |
| 297 // close the codec contexts here because the corresponding codecs are opened | 301 // close the codec contexts here because the corresponding codecs are opened |
| 298 // in the decoder filters. By reaching this point, all filters should have | 302 // in the decoder filters. By reaching this point, all filters should have |
| 299 // stopped, so this is the only safe place to do the global clean up. | 303 // stopped, so this is the only safe place to do the global clean up. |
| 300 // TODO(hclam): close the codecs in the corresponding decoders. | 304 // TODO(hclam): close the codecs in the corresponding decoders. |
| 301 if (!format_context_) | 305 if (!format_context_) |
| 302 return; | 306 return; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 322 void FFmpegDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) { | 326 void FFmpegDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) { |
| 323 message_loop_->PostTask(FROM_HERE, | 327 message_loop_->PostTask(FROM_HERE, |
| 324 base::Bind(&FFmpegDemuxer::SeekTask, this, time, cb)); | 328 base::Bind(&FFmpegDemuxer::SeekTask, this, time, cb)); |
| 325 } | 329 } |
| 326 | 330 |
| 327 void FFmpegDemuxer::SetPlaybackRate(float playback_rate) { | 331 void FFmpegDemuxer::SetPlaybackRate(float playback_rate) { |
| 328 DCHECK(data_source_.get()); | 332 DCHECK(data_source_.get()); |
| 329 data_source_->SetPlaybackRate(playback_rate); | 333 data_source_->SetPlaybackRate(playback_rate); |
| 330 } | 334 } |
| 331 | 335 |
| 332 void FFmpegDemuxer::SetPreload(Preload preload) { | |
| 333 DCHECK(data_source_.get()); | |
| 334 data_source_->SetPreload(preload); | |
| 335 } | |
| 336 | |
| 337 void FFmpegDemuxer::OnAudioRendererDisabled() { | 336 void FFmpegDemuxer::OnAudioRendererDisabled() { |
| 338 message_loop_->PostTask(FROM_HERE, base::Bind( | 337 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 339 &FFmpegDemuxer::DisableAudioStreamTask, this)); | 338 &FFmpegDemuxer::DisableAudioStreamTask, this)); |
| 340 } | 339 } |
| 341 | 340 |
| 342 void FFmpegDemuxer::set_host(DemuxerHost* demuxer_host) { | 341 void FFmpegDemuxer::set_host(DemuxerHost* demuxer_host) { |
| 343 Demuxer::set_host(demuxer_host); | 342 Demuxer::set_host(demuxer_host); |
| 344 if (data_source_) | 343 data_source_->set_host(demuxer_host); |
| 345 data_source_->set_host(demuxer_host); | |
| 346 if (max_duration_.InMicroseconds() >= 0) | |
| 347 host()->SetDuration(max_duration_); | |
| 348 if (read_position_ > 0) | |
| 349 host()->SetCurrentReadPosition(read_position_); | |
| 350 if (deferred_status_ != PIPELINE_OK) | |
| 351 host()->OnDemuxerError(deferred_status_); | |
| 352 } | 344 } |
| 353 | 345 |
| 354 void FFmpegDemuxer::Initialize(DataSource* data_source, | 346 void FFmpegDemuxer::Initialize(const PipelineStatusCB& status_cb) { |
| 355 const PipelineStatusCB& status_cb) { | 347 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 356 message_loop_->PostTask( | 348 &FFmpegDemuxer::InitializeTask, this, status_cb)); |
| 357 FROM_HERE, | |
| 358 base::Bind(&FFmpegDemuxer::InitializeTask, this, | |
| 359 make_scoped_refptr(data_source), status_cb)); | |
| 360 } | 349 } |
| 361 | 350 |
| 362 scoped_refptr<DemuxerStream> FFmpegDemuxer::GetStream( | 351 scoped_refptr<DemuxerStream> FFmpegDemuxer::GetStream( |
| 363 DemuxerStream::Type type) { | 352 DemuxerStream::Type type) { |
| 364 StreamVector::iterator iter; | 353 StreamVector::iterator iter; |
| 365 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { | 354 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { |
| 366 if (*iter && (*iter)->type() == type) { | 355 if (*iter && (*iter)->type() == type) { |
| 367 return *iter; | 356 return *iter; |
| 368 } | 357 } |
| 369 } | 358 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 390 | 379 |
| 391 // Asynchronous read from data source. | 380 // Asynchronous read from data source. |
| 392 data_source_->Read(read_position_, size, data, base::Bind( | 381 data_source_->Read(read_position_, size, data, base::Bind( |
| 393 &FFmpegDemuxer::SignalReadCompleted, this)); | 382 &FFmpegDemuxer::SignalReadCompleted, this)); |
| 394 | 383 |
| 395 // TODO(hclam): The method is called on the demuxer thread and this method | 384 // TODO(hclam): The method is called on the demuxer thread and this method |
| 396 // call will block the thread. We need to implemented an additional thread to | 385 // call will block the thread. We need to implemented an additional thread to |
| 397 // let FFmpeg demuxer methods to run on. | 386 // let FFmpeg demuxer methods to run on. |
| 398 int last_read_bytes = WaitForRead(); | 387 int last_read_bytes = WaitForRead(); |
| 399 if (last_read_bytes == DataSource::kReadError) { | 388 if (last_read_bytes == DataSource::kReadError) { |
| 400 if (host()) | 389 host()->OnDemuxerError(PIPELINE_ERROR_READ); |
| 401 host()->OnDemuxerError(PIPELINE_ERROR_READ); | |
| 402 else | |
| 403 deferred_status_ = PIPELINE_ERROR_READ; | |
| 404 | 390 |
| 405 // Returns with a negative number to signal an error to FFmpeg. | 391 // Returns with a negative number to signal an error to FFmpeg. |
| 406 read_has_failed_ = true; | 392 read_has_failed_ = true; |
| 407 return AVERROR(EIO); | 393 return AVERROR(EIO); |
| 408 } | 394 } |
| 409 read_position_ += last_read_bytes; | 395 read_position_ += last_read_bytes; |
| 410 | 396 host()->SetCurrentReadPosition(read_position_); |
| 411 if (host()) | |
| 412 host()->SetCurrentReadPosition(read_position_); | |
| 413 | 397 |
| 414 return last_read_bytes; | 398 return last_read_bytes; |
| 415 } | 399 } |
| 416 | 400 |
| 417 bool FFmpegDemuxer::GetPosition(int64* position_out) { | 401 bool FFmpegDemuxer::GetPosition(int64* position_out) { |
| 418 *position_out = read_position_; | 402 *position_out = read_position_; |
| 419 return true; | 403 return true; |
| 420 } | 404 } |
| 421 | 405 |
| 422 bool FFmpegDemuxer::SetPosition(int64 position) { | 406 bool FFmpegDemuxer::SetPosition(int64 position) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 441 bool FFmpegDemuxer::IsStreaming() { | 425 bool FFmpegDemuxer::IsStreaming() { |
| 442 DCHECK(data_source_); | 426 DCHECK(data_source_); |
| 443 | 427 |
| 444 return data_source_->IsStreaming(); | 428 return data_source_->IsStreaming(); |
| 445 } | 429 } |
| 446 | 430 |
| 447 MessageLoop* FFmpegDemuxer::message_loop() { | 431 MessageLoop* FFmpegDemuxer::message_loop() { |
| 448 return message_loop_; | 432 return message_loop_; |
| 449 } | 433 } |
| 450 | 434 |
| 451 void FFmpegDemuxer::InitializeTask(DataSource* data_source, | 435 // Helper for calculating the bitrate of the media based on information stored |
| 452 const PipelineStatusCB& status_cb) { | 436 // in |format_context| or failing that the size and duration of the media. |
| 437 // |
| 438 // Returns 0 if a bitrate could not be determined. |
| 439 static int CalculateBitrate( |
| 440 AVFormatContext* format_context, |
| 441 const base::TimeDelta& duration, |
| 442 int64 filesize_in_bytes) { |
| 443 // If there is a bitrate set on the container, use it. |
| 444 if (format_context->bit_rate > 0) |
| 445 return format_context->bit_rate; |
| 446 |
| 447 // Then try to sum the bitrates individually per stream. |
| 448 int bitrate = 0; |
| 449 for (size_t i = 0; i < format_context->nb_streams; ++i) { |
| 450 AVCodecContext* codec_context = format_context->streams[i]->codec; |
| 451 bitrate += codec_context->bit_rate; |
| 452 } |
| 453 if (bitrate > 0) |
| 454 return bitrate; |
| 455 |
| 456 // See if we can approximate the bitrate as long as we have a filesize and |
| 457 // valid duration. |
| 458 if (duration.InMicroseconds() <= 0 || |
| 459 duration == kInfiniteDuration() || |
| 460 filesize_in_bytes == 0) { |
| 461 return 0; |
| 462 } |
| 463 |
| 464 // Do math in floating point as we'd overflow an int64 if the filesize was |
| 465 // larger than ~1073GB. |
| 466 double bytes = filesize_in_bytes; |
| 467 double duration_us = duration.InMicroseconds(); |
| 468 return bytes * 8000000.0 / duration_us; |
| 469 } |
| 470 |
| 471 void FFmpegDemuxer::InitializeTask(const PipelineStatusCB& status_cb) { |
| 453 DCHECK_EQ(MessageLoop::current(), message_loop_); | 472 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 454 | 473 |
| 455 data_source_ = data_source; | |
| 456 if (host()) | |
| 457 data_source_->set_host(host()); | |
| 458 | |
| 459 // Add ourself to Protocol list and get our unique key. | 474 // Add ourself to Protocol list and get our unique key. |
| 460 std::string key = FFmpegGlue::GetInstance()->AddProtocol(this); | 475 std::string key = FFmpegGlue::GetInstance()->AddProtocol(this); |
| 461 | 476 |
| 462 // Open FFmpeg AVFormatContext. | 477 // Open FFmpeg AVFormatContext. |
| 463 DCHECK(!format_context_); | 478 DCHECK(!format_context_); |
| 464 AVFormatContext* context = NULL; | 479 AVFormatContext* context = NULL; |
| 465 int result = avformat_open_input(&context, key.c_str(), NULL, NULL); | 480 int result = avformat_open_input(&context, key.c_str(), NULL, NULL); |
| 466 | 481 |
| 467 // Remove ourself from protocol list. | 482 // Remove ourself from protocol list. |
| 468 FFmpegGlue::GetInstance()->RemoveProtocol(this); | 483 FFmpegGlue::GetInstance()->RemoveProtocol(this); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 536 max_duration = kInfiniteDuration(); | 551 max_duration = kInfiniteDuration(); |
| 537 } | 552 } |
| 538 | 553 |
| 539 // Some demuxers, like WAV, do not put timestamps on their frames. We | 554 // Some demuxers, like WAV, do not put timestamps on their frames. We |
| 540 // assume the the start time is 0. | 555 // assume the the start time is 0. |
| 541 if (start_time_ == kNoTimestamp()) | 556 if (start_time_ == kNoTimestamp()) |
| 542 start_time_ = base::TimeDelta(); | 557 start_time_ = base::TimeDelta(); |
| 543 | 558 |
| 544 // Good to go: set the duration and bitrate and notify we're done | 559 // Good to go: set the duration and bitrate and notify we're done |
| 545 // initializing. | 560 // initializing. |
| 546 if (host()) | 561 host()->SetDuration(max_duration); |
| 547 host()->SetDuration(max_duration); | |
| 548 max_duration_ = max_duration; | |
| 549 | 562 |
| 550 int bitrate = GetBitrate(); | 563 int64 filesize_in_bytes = 0; |
| 551 if (bitrate > 0) | 564 GetSize(&filesize_in_bytes); |
| 552 data_source_->SetBitrate(bitrate); | 565 bitrate_ = CalculateBitrate(format_context_, max_duration, filesize_in_bytes); |
| 566 if (bitrate_ > 0) |
| 567 data_source_->SetBitrate(bitrate_); |
| 553 | 568 |
| 554 status_cb.Run(PIPELINE_OK); | 569 status_cb.Run(PIPELINE_OK); |
| 555 } | 570 } |
| 556 | 571 |
| 572 |
| 557 int FFmpegDemuxer::GetBitrate() { | 573 int FFmpegDemuxer::GetBitrate() { |
| 558 DCHECK(format_context_); | 574 DCHECK(format_context_) << "Initialize() has not been called"; |
| 559 | 575 return bitrate_; |
| 560 // If there is a bitrate set on the container, use it. | |
| 561 if (format_context_->bit_rate > 0) | |
| 562 return format_context_->bit_rate; | |
| 563 | |
| 564 // Then try to sum the bitrates individually per stream. | |
| 565 int bitrate = 0; | |
| 566 for (size_t i = 0; i < format_context_->nb_streams; ++i) { | |
| 567 AVCodecContext* codec_context = format_context_->streams[i]->codec; | |
| 568 bitrate += codec_context->bit_rate; | |
| 569 } | |
| 570 if (bitrate > 0) | |
| 571 return bitrate; | |
| 572 | |
| 573 // See if we can approximate the bitrate as long as we have a filesize and | |
| 574 // valid duration. | |
| 575 int64 filesize_in_bytes; | |
| 576 if (max_duration_.InMicroseconds() <= 0 || | |
| 577 max_duration_ == kInfiniteDuration() || | |
| 578 !GetSize(&filesize_in_bytes)) { | |
| 579 return 0; | |
| 580 } | |
| 581 | |
| 582 // Do math in floating point as we'd overflow an int64 if the filesize was | |
| 583 // larger than ~1073GB. | |
| 584 double bytes = filesize_in_bytes; | |
| 585 double duration = max_duration_.InMicroseconds(); | |
| 586 return bytes * 8000000.0 / duration; | |
| 587 } | 576 } |
| 588 | 577 |
| 589 bool FFmpegDemuxer::IsLocalSource() { | 578 bool FFmpegDemuxer::IsLocalSource() { |
| 590 return local_source_; | 579 return local_source_; |
| 591 } | 580 } |
| 592 | 581 |
| 593 bool FFmpegDemuxer::IsSeekable() { | 582 bool FFmpegDemuxer::IsSeekable() { |
| 594 return !IsStreaming(); | 583 return !IsStreaming(); |
| 595 } | 584 } |
| 596 | 585 |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 737 read_event_.Wait(); | 726 read_event_.Wait(); |
| 738 return last_read_bytes_; | 727 return last_read_bytes_; |
| 739 } | 728 } |
| 740 | 729 |
| 741 void FFmpegDemuxer::SignalReadCompleted(int size) { | 730 void FFmpegDemuxer::SignalReadCompleted(int size) { |
| 742 last_read_bytes_ = size; | 731 last_read_bytes_ = size; |
| 743 read_event_.Signal(); | 732 read_event_.Signal(); |
| 744 } | 733 } |
| 745 | 734 |
| 746 } // namespace media | 735 } // namespace media |
| OLD | NEW |