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

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

Issue 9860027: Remove DemuxerFactory and URL parameter from Pipeline. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src
Patch Set: again Created 8 years, 8 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 | Annotate | Revision Log
« 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) 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
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
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
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
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
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
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
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