| 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 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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( | 279 FFmpegDemuxer::FFmpegDemuxer( |
| 280 MessageLoop* message_loop, | 280 MessageLoop* message_loop, |
| 281 const scoped_refptr<DataSource>& data_source, | 281 const scoped_refptr<DataSource>& data_source, |
| 282 bool local_source) | 282 bool local_source) |
| 283 : message_loop_(message_loop), | 283 : host_(NULL), |
| 284 message_loop_(message_loop), |
| 284 local_source_(local_source), | 285 local_source_(local_source), |
| 285 format_context_(NULL), | 286 format_context_(NULL), |
| 286 data_source_(data_source), | 287 data_source_(data_source), |
| 287 read_event_(false, false), | 288 read_event_(false, false), |
| 288 read_has_failed_(false), | 289 read_has_failed_(false), |
| 289 last_read_bytes_(0), | 290 last_read_bytes_(0), |
| 290 read_position_(0), | 291 read_position_(0), |
| 291 bitrate_(0), | 292 bitrate_(0), |
| 292 first_seek_hack_(true), | 293 first_seek_hack_(true), |
| 293 start_time_(kNoTimestamp()), | 294 start_time_(kNoTimestamp()), |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 331 void FFmpegDemuxer::SetPlaybackRate(float playback_rate) { | 332 void FFmpegDemuxer::SetPlaybackRate(float playback_rate) { |
| 332 DCHECK(data_source_.get()); | 333 DCHECK(data_source_.get()); |
| 333 data_source_->SetPlaybackRate(playback_rate); | 334 data_source_->SetPlaybackRate(playback_rate); |
| 334 } | 335 } |
| 335 | 336 |
| 336 void FFmpegDemuxer::OnAudioRendererDisabled() { | 337 void FFmpegDemuxer::OnAudioRendererDisabled() { |
| 337 message_loop_->PostTask(FROM_HERE, base::Bind( | 338 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 338 &FFmpegDemuxer::DisableAudioStreamTask, this)); | 339 &FFmpegDemuxer::DisableAudioStreamTask, this)); |
| 339 } | 340 } |
| 340 | 341 |
| 341 void FFmpegDemuxer::set_host(DemuxerHost* demuxer_host) { | 342 void FFmpegDemuxer::Initialize(DemuxerHost* host, |
| 342 Demuxer::set_host(demuxer_host); | 343 const PipelineStatusCB& status_cb) { |
| 343 data_source_->set_host(demuxer_host); | |
| 344 } | |
| 345 | |
| 346 void FFmpegDemuxer::Initialize(const PipelineStatusCB& status_cb) { | |
| 347 message_loop_->PostTask(FROM_HERE, base::Bind( | 344 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 348 &FFmpegDemuxer::InitializeTask, this, status_cb)); | 345 &FFmpegDemuxer::InitializeTask, this, host, status_cb)); |
| 349 } | 346 } |
| 350 | 347 |
| 351 scoped_refptr<DemuxerStream> FFmpegDemuxer::GetStream( | 348 scoped_refptr<DemuxerStream> FFmpegDemuxer::GetStream( |
| 352 DemuxerStream::Type type) { | 349 DemuxerStream::Type type) { |
| 353 StreamVector::iterator iter; | 350 StreamVector::iterator iter; |
| 354 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { | 351 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { |
| 355 if (*iter && (*iter)->type() == type) { | 352 if (*iter && (*iter)->type() == type) { |
| 356 return *iter; | 353 return *iter; |
| 357 } | 354 } |
| 358 } | 355 } |
| 359 return NULL; | 356 return NULL; |
| 360 } | 357 } |
| 361 | 358 |
| 362 base::TimeDelta FFmpegDemuxer::GetStartTime() const { | 359 base::TimeDelta FFmpegDemuxer::GetStartTime() const { |
| 363 return start_time_; | 360 return start_time_; |
| 364 } | 361 } |
| 365 | 362 |
| 366 size_t FFmpegDemuxer::Read(size_t size, uint8* data) { | 363 size_t FFmpegDemuxer::Read(size_t size, uint8* data) { |
| 364 DCHECK(host_); |
| 367 DCHECK(data_source_); | 365 DCHECK(data_source_); |
| 368 | 366 |
| 369 // If read has ever failed, return with an error. | 367 // If read has ever failed, return with an error. |
| 370 // TODO(hclam): use a more meaningful constant as error. | 368 // TODO(hclam): use a more meaningful constant as error. |
| 371 if (read_has_failed_) | 369 if (read_has_failed_) |
| 372 return AVERROR(EIO); | 370 return AVERROR(EIO); |
| 373 | 371 |
| 374 // Even though FFmpeg defines AVERROR_EOF, it's not to be used with I/O | 372 // Even though FFmpeg defines AVERROR_EOF, it's not to be used with I/O |
| 375 // routines. Instead return 0 for any read at or past EOF. | 373 // routines. Instead return 0 for any read at or past EOF. |
| 376 int64 file_size; | 374 int64 file_size; |
| 377 if (data_source_->GetSize(&file_size) && read_position_ >= file_size) | 375 if (data_source_->GetSize(&file_size) && read_position_ >= file_size) |
| 378 return 0; | 376 return 0; |
| 379 | 377 |
| 380 // Asynchronous read from data source. | 378 // Asynchronous read from data source. |
| 381 data_source_->Read(read_position_, size, data, base::Bind( | 379 data_source_->Read(read_position_, size, data, base::Bind( |
| 382 &FFmpegDemuxer::SignalReadCompleted, this)); | 380 &FFmpegDemuxer::SignalReadCompleted, this)); |
| 383 | 381 |
| 384 // TODO(hclam): The method is called on the demuxer thread and this method | 382 // TODO(hclam): The method is called on the demuxer thread and this method |
| 385 // call will block the thread. We need to implemented an additional thread to | 383 // call will block the thread. We need to implemented an additional thread to |
| 386 // let FFmpeg demuxer methods to run on. | 384 // let FFmpeg demuxer methods to run on. |
| 387 int last_read_bytes = WaitForRead(); | 385 int last_read_bytes = WaitForRead(); |
| 388 if (last_read_bytes == DataSource::kReadError) { | 386 if (last_read_bytes == DataSource::kReadError) { |
| 389 host()->OnDemuxerError(PIPELINE_ERROR_READ); | 387 host_->OnDemuxerError(PIPELINE_ERROR_READ); |
| 390 | 388 |
| 391 // Returns with a negative number to signal an error to FFmpeg. | 389 // Returns with a negative number to signal an error to FFmpeg. |
| 392 read_has_failed_ = true; | 390 read_has_failed_ = true; |
| 393 return AVERROR(EIO); | 391 return AVERROR(EIO); |
| 394 } | 392 } |
| 395 read_position_ += last_read_bytes; | 393 read_position_ += last_read_bytes; |
| 396 host()->SetCurrentReadPosition(read_position_); | 394 host_->SetCurrentReadPosition(read_position_); |
| 397 | 395 |
| 398 return last_read_bytes; | 396 return last_read_bytes; |
| 399 } | 397 } |
| 400 | 398 |
| 401 bool FFmpegDemuxer::GetPosition(int64* position_out) { | 399 bool FFmpegDemuxer::GetPosition(int64* position_out) { |
| 400 DCHECK(host_); |
| 402 *position_out = read_position_; | 401 *position_out = read_position_; |
| 403 return true; | 402 return true; |
| 404 } | 403 } |
| 405 | 404 |
| 406 bool FFmpegDemuxer::SetPosition(int64 position) { | 405 bool FFmpegDemuxer::SetPosition(int64 position) { |
| 406 DCHECK(host_); |
| 407 DCHECK(data_source_); | 407 DCHECK(data_source_); |
| 408 | 408 |
| 409 int64 file_size; | 409 int64 file_size; |
| 410 if ((data_source_->GetSize(&file_size) && position >= file_size) || | 410 if ((data_source_->GetSize(&file_size) && position >= file_size) || |
| 411 position < 0) { | 411 position < 0) { |
| 412 return false; | 412 return false; |
| 413 } | 413 } |
| 414 | 414 |
| 415 read_position_ = position; | 415 read_position_ = position; |
| 416 return true; | 416 return true; |
| 417 } | 417 } |
| 418 | 418 |
| 419 bool FFmpegDemuxer::GetSize(int64* size_out) { | 419 bool FFmpegDemuxer::GetSize(int64* size_out) { |
| 420 DCHECK(host_); |
| 420 DCHECK(data_source_); | 421 DCHECK(data_source_); |
| 421 | |
| 422 return data_source_->GetSize(size_out); | 422 return data_source_->GetSize(size_out); |
| 423 } | 423 } |
| 424 | 424 |
| 425 bool FFmpegDemuxer::IsStreaming() { | 425 bool FFmpegDemuxer::IsStreaming() { |
| 426 DCHECK(host_); |
| 426 DCHECK(data_source_); | 427 DCHECK(data_source_); |
| 427 | |
| 428 return data_source_->IsStreaming(); | 428 return data_source_->IsStreaming(); |
| 429 } | 429 } |
| 430 | 430 |
| 431 MessageLoop* FFmpegDemuxer::message_loop() { | 431 MessageLoop* FFmpegDemuxer::message_loop() { |
| 432 return message_loop_; | 432 return message_loop_; |
| 433 } | 433 } |
| 434 | 434 |
| 435 // Helper for calculating the bitrate of the media based on information stored | 435 // Helper for calculating the bitrate of the media based on information stored |
| 436 // in |format_context| or failing that the size and duration of the media. | 436 // in |format_context| or failing that the size and duration of the media. |
| 437 // | 437 // |
| (...skipping 23 matching lines...) Expand all Loading... |
| 461 return 0; | 461 return 0; |
| 462 } | 462 } |
| 463 | 463 |
| 464 // Do math in floating point as we'd overflow an int64 if the filesize was | 464 // Do math in floating point as we'd overflow an int64 if the filesize was |
| 465 // larger than ~1073GB. | 465 // larger than ~1073GB. |
| 466 double bytes = filesize_in_bytes; | 466 double bytes = filesize_in_bytes; |
| 467 double duration_us = duration.InMicroseconds(); | 467 double duration_us = duration.InMicroseconds(); |
| 468 return bytes * 8000000.0 / duration_us; | 468 return bytes * 8000000.0 / duration_us; |
| 469 } | 469 } |
| 470 | 470 |
| 471 void FFmpegDemuxer::InitializeTask(const PipelineStatusCB& status_cb) { | 471 void FFmpegDemuxer::InitializeTask(DemuxerHost* host, |
| 472 const PipelineStatusCB& status_cb) { |
| 472 DCHECK_EQ(MessageLoop::current(), message_loop_); | 473 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 474 host_ = host; |
| 475 |
| 476 // TODO(scherkus): DataSource should have a host by this point, |
| 477 // see http://crbug.com/122071 |
| 478 data_source_->set_host(host); |
| 473 | 479 |
| 474 // Add ourself to Protocol list and get our unique key. | 480 // Add ourself to Protocol list and get our unique key. |
| 475 std::string key = FFmpegGlue::GetInstance()->AddProtocol(this); | 481 std::string key = FFmpegGlue::GetInstance()->AddProtocol(this); |
| 476 | 482 |
| 477 // Open FFmpeg AVFormatContext. | 483 // Open FFmpeg AVFormatContext. |
| 478 DCHECK(!format_context_); | 484 DCHECK(!format_context_); |
| 479 AVFormatContext* context = NULL; | 485 AVFormatContext* context = NULL; |
| 480 int result = avformat_open_input(&context, key.c_str(), NULL, NULL); | 486 int result = avformat_open_input(&context, key.c_str(), NULL, NULL); |
| 481 | 487 |
| 482 // Remove ourself from protocol list. | 488 // Remove ourself from protocol list. |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 551 max_duration = kInfiniteDuration(); | 557 max_duration = kInfiniteDuration(); |
| 552 } | 558 } |
| 553 | 559 |
| 554 // Some demuxers, like WAV, do not put timestamps on their frames. We | 560 // Some demuxers, like WAV, do not put timestamps on their frames. We |
| 555 // assume the the start time is 0. | 561 // assume the the start time is 0. |
| 556 if (start_time_ == kNoTimestamp()) | 562 if (start_time_ == kNoTimestamp()) |
| 557 start_time_ = base::TimeDelta(); | 563 start_time_ = base::TimeDelta(); |
| 558 | 564 |
| 559 // Good to go: set the duration and bitrate and notify we're done | 565 // Good to go: set the duration and bitrate and notify we're done |
| 560 // initializing. | 566 // initializing. |
| 561 host()->SetDuration(max_duration); | 567 host_->SetDuration(max_duration); |
| 562 | 568 |
| 563 int64 filesize_in_bytes = 0; | 569 int64 filesize_in_bytes = 0; |
| 564 GetSize(&filesize_in_bytes); | 570 GetSize(&filesize_in_bytes); |
| 565 bitrate_ = CalculateBitrate(format_context_, max_duration, filesize_in_bytes); | 571 bitrate_ = CalculateBitrate(format_context_, max_duration, filesize_in_bytes); |
| 566 if (bitrate_ > 0) | 572 if (bitrate_ > 0) |
| 567 data_source_->SetBitrate(bitrate_); | 573 data_source_->SetBitrate(bitrate_); |
| 568 | 574 |
| 569 status_cb.Run(PIPELINE_OK); | 575 status_cb.Run(PIPELINE_OK); |
| 570 } | 576 } |
| 571 | 577 |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 726 read_event_.Wait(); | 732 read_event_.Wait(); |
| 727 return last_read_bytes_; | 733 return last_read_bytes_; |
| 728 } | 734 } |
| 729 | 735 |
| 730 void FFmpegDemuxer::SignalReadCompleted(int size) { | 736 void FFmpegDemuxer::SignalReadCompleted(int size) { |
| 731 last_read_bytes_ = size; | 737 last_read_bytes_ = size; |
| 732 read_event_.Signal(); | 738 read_event_.Signal(); |
| 733 } | 739 } |
| 734 | 740 |
| 735 } // namespace media | 741 } // namespace media |
| OLD | NEW |