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

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

Issue 11410052: Refactor FFmpegURLProtocol code from FFmpegDemuxer into BlockingUrlProtocol. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix android Created 8 years, 1 month 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
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/bind.h" 10 #include "base/bind.h"
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after
256 256
257 // 257 //
258 // FFmpegDemuxer 258 // FFmpegDemuxer
259 // 259 //
260 FFmpegDemuxer::FFmpegDemuxer( 260 FFmpegDemuxer::FFmpegDemuxer(
261 const scoped_refptr<base::MessageLoopProxy>& message_loop, 261 const scoped_refptr<base::MessageLoopProxy>& message_loop,
262 const scoped_refptr<DataSource>& data_source) 262 const scoped_refptr<DataSource>& data_source)
263 : host_(NULL), 263 : host_(NULL),
264 message_loop_(message_loop), 264 message_loop_(message_loop),
265 data_source_(data_source), 265 data_source_(data_source),
266 read_event_(false, false),
267 read_has_failed_(false),
268 last_read_bytes_(0),
269 read_position_(0),
270 bitrate_(0), 266 bitrate_(0),
271 start_time_(kNoTimestamp()), 267 start_time_(kNoTimestamp()),
272 audio_disabled_(false), 268 audio_disabled_(false),
273 duration_known_(false) { 269 duration_known_(false),
270 url_protocol_(data_source, base::Bind(
271 &FFmpegDemuxer::OnDataSourceError, base::Unretained(this))) {
274 DCHECK(message_loop_); 272 DCHECK(message_loop_);
275 DCHECK(data_source_); 273 DCHECK(data_source_);
276 } 274 }
277 275
278 FFmpegDemuxer::~FFmpegDemuxer() {} 276 FFmpegDemuxer::~FFmpegDemuxer() {}
279 277
280 void FFmpegDemuxer::PostDemuxTask() { 278 void FFmpegDemuxer::PostDemuxTask() {
281 message_loop_->PostTask(FROM_HERE, 279 message_loop_->PostTask(FROM_HERE,
282 base::Bind(&FFmpegDemuxer::DemuxTask, this)); 280 base::Bind(&FFmpegDemuxer::DemuxTask, this));
283 } 281 }
284 282
285 void FFmpegDemuxer::Stop(const base::Closure& callback) { 283 void FFmpegDemuxer::Stop(const base::Closure& callback) {
286 // Post a task to notify the streams to stop as well. 284 // Post a task to notify the streams to stop as well.
287 message_loop_->PostTask(FROM_HERE, 285 message_loop_->PostTask(FROM_HERE,
288 base::Bind(&FFmpegDemuxer::StopTask, this, callback)); 286 base::Bind(&FFmpegDemuxer::StopTask, this, callback));
289 287
290 // Then wakes up the thread from reading. 288 // TODO(scherkus): This should be on |message_loop_| but today that thread is
291 SignalReadCompleted(DataSource::kReadError); 289 // potentially blocked. Move to StopTask() after all blocking calls are
290 // guaranteed to run on a separate thread.
291 url_protocol_.Abort();
292 } 292 }
293 293
294 void FFmpegDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) { 294 void FFmpegDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) {
295 message_loop_->PostTask(FROM_HERE, 295 message_loop_->PostTask(FROM_HERE,
296 base::Bind(&FFmpegDemuxer::SeekTask, this, time, cb)); 296 base::Bind(&FFmpegDemuxer::SeekTask, this, time, cb));
297 } 297 }
298 298
299 void FFmpegDemuxer::SetPlaybackRate(float playback_rate) { 299 void FFmpegDemuxer::SetPlaybackRate(float playback_rate) {
300 DCHECK(data_source_.get()); 300 DCHECK(data_source_.get());
301 data_source_->SetPlaybackRate(playback_rate); 301 data_source_->SetPlaybackRate(playback_rate);
(...skipping 23 matching lines...) Expand all
325 return *iter; 325 return *iter;
326 } 326 }
327 } 327 }
328 return NULL; 328 return NULL;
329 } 329 }
330 330
331 base::TimeDelta FFmpegDemuxer::GetStartTime() const { 331 base::TimeDelta FFmpegDemuxer::GetStartTime() const {
332 return start_time_; 332 return start_time_;
333 } 333 }
334 334
335 int FFmpegDemuxer::Read(int size, uint8* data) {
336 DCHECK(host_);
337 DCHECK(data_source_);
338
339 // If read has ever failed, return with an error.
340 // TODO(hclam): use a more meaningful constant as error.
341 if (read_has_failed_)
342 return AVERROR(EIO);
343
344 // Even though FFmpeg defines AVERROR_EOF, it's not to be used with I/O
345 // routines. Instead return 0 for any read at or past EOF.
346 int64 file_size;
347 if (data_source_->GetSize(&file_size) && read_position_ >= file_size)
348 return 0;
349
350 // Asynchronous read from data source.
351 data_source_->Read(read_position_, size, data, base::Bind(
352 &FFmpegDemuxer::SignalReadCompleted, this));
353
354 // TODO(hclam): The method is called on the demuxer thread and this method
355 // call will block the thread. We need to implemented an additional thread to
356 // let FFmpeg demuxer methods to run on.
357 int last_read_bytes = WaitForRead();
358 if (last_read_bytes == DataSource::kReadError) {
359 host_->OnDemuxerError(PIPELINE_ERROR_READ);
360
361 // Returns with a negative number to signal an error to FFmpeg.
362 read_has_failed_ = true;
363 return AVERROR(EIO);
364 }
365 read_position_ += last_read_bytes;
366
367 return last_read_bytes;
368 }
369
370 bool FFmpegDemuxer::GetPosition(int64* position_out) {
371 DCHECK(host_);
372 *position_out = read_position_;
373 return true;
374 }
375
376 bool FFmpegDemuxer::SetPosition(int64 position) {
377 DCHECK(host_);
378 DCHECK(data_source_);
379
380 int64 file_size;
381 if ((data_source_->GetSize(&file_size) && position >= file_size) ||
382 position < 0) {
383 return false;
384 }
385
386 read_position_ = position;
387 return true;
388 }
389
390 bool FFmpegDemuxer::GetSize(int64* size_out) {
391 DCHECK(host_);
392 DCHECK(data_source_);
393 return data_source_->GetSize(size_out);
394 }
395
396 bool FFmpegDemuxer::IsStreaming() {
397 DCHECK(host_);
398 DCHECK(data_source_);
399 return data_source_->IsStreaming();
400 }
401
402 scoped_refptr<base::MessageLoopProxy> FFmpegDemuxer::message_loop() { 335 scoped_refptr<base::MessageLoopProxy> FFmpegDemuxer::message_loop() {
403 return message_loop_; 336 return message_loop_;
404 } 337 }
405 338
406 // Helper for calculating the bitrate of the media based on information stored 339 // Helper for calculating the bitrate of the media based on information stored
407 // in |format_context| or failing that the size and duration of the media. 340 // in |format_context| or failing that the size and duration of the media.
408 // 341 //
409 // Returns 0 if a bitrate could not be determined. 342 // Returns 0 if a bitrate could not be determined.
410 static int CalculateBitrate( 343 static int CalculateBitrate(
411 AVFormatContext* format_context, 344 AVFormatContext* format_context,
(...skipping 29 matching lines...) Expand all
441 374
442 void FFmpegDemuxer::InitializeTask(DemuxerHost* host, 375 void FFmpegDemuxer::InitializeTask(DemuxerHost* host,
443 const PipelineStatusCB& status_cb) { 376 const PipelineStatusCB& status_cb) {
444 DCHECK(message_loop_->BelongsToCurrentThread()); 377 DCHECK(message_loop_->BelongsToCurrentThread());
445 host_ = host; 378 host_ = host;
446 379
447 // TODO(scherkus): DataSource should have a host by this point, 380 // TODO(scherkus): DataSource should have a host by this point,
448 // see http://crbug.com/122071 381 // see http://crbug.com/122071
449 data_source_->set_host(host); 382 data_source_->set_host(host);
450 383
451 glue_.reset(new FFmpegGlue(this)); 384 glue_.reset(new FFmpegGlue(&url_protocol_));
452 AVFormatContext* format_context = glue_->format_context(); 385 AVFormatContext* format_context = glue_->format_context();
453 386
454 // Disable ID3v1 tag reading to avoid costly seeks to end of file for data we 387 // Disable ID3v1 tag reading to avoid costly seeks to end of file for data we
455 // don't use. FFmpeg will only read ID3v1 tags if no other metadata is 388 // don't use. FFmpeg will only read ID3v1 tags if no other metadata is
456 // available, so add a metadata entry to ensure some is always present. 389 // available, so add a metadata entry to ensure some is always present.
457 av_dict_set(&format_context->metadata, "skip_id3v1_tags", "", 0); 390 av_dict_set(&format_context->metadata, "skip_id3v1_tags", "", 0);
458 391
459 if (!glue_->OpenContext()) { 392 if (!glue_->OpenContext()) {
460 status_cb.Run(DEMUXER_ERROR_COULD_NOT_OPEN); 393 status_cb.Run(DEMUXER_ERROR_COULD_NOT_OPEN);
461 return; 394 return;
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
532 // assume the the start time is 0. 465 // assume the the start time is 0.
533 if (start_time_ == kNoTimestamp()) 466 if (start_time_ == kNoTimestamp())
534 start_time_ = base::TimeDelta(); 467 start_time_ = base::TimeDelta();
535 468
536 // Good to go: set the duration and bitrate and notify we're done 469 // Good to go: set the duration and bitrate and notify we're done
537 // initializing. 470 // initializing.
538 host_->SetDuration(max_duration); 471 host_->SetDuration(max_duration);
539 duration_known_ = (max_duration != kInfiniteDuration()); 472 duration_known_ = (max_duration != kInfiniteDuration());
540 473
541 int64 filesize_in_bytes = 0; 474 int64 filesize_in_bytes = 0;
542 GetSize(&filesize_in_bytes); 475 url_protocol_.GetSize(&filesize_in_bytes);
543 bitrate_ = CalculateBitrate(format_context, max_duration, filesize_in_bytes); 476 bitrate_ = CalculateBitrate(format_context, max_duration, filesize_in_bytes);
544 if (bitrate_ > 0) 477 if (bitrate_ > 0)
545 data_source_->SetBitrate(bitrate_); 478 data_source_->SetBitrate(bitrate_);
546 479
547 status_cb.Run(PIPELINE_OK); 480 status_cb.Run(PIPELINE_OK);
548 } 481 }
549 482
550 void FFmpegDemuxer::SeekTask(base::TimeDelta time, const PipelineStatusCB& cb) { 483 void FFmpegDemuxer::SeekTask(base::TimeDelta time, const PipelineStatusCB& cb) {
551 DCHECK(message_loop_->BelongsToCurrentThread()); 484 DCHECK(message_loop_->BelongsToCurrentThread());
552 485
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
676 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { 609 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
677 if (!*iter || 610 if (!*iter ||
678 (audio_disabled_ && (*iter)->type() == DemuxerStream::AUDIO)) { 611 (audio_disabled_ && (*iter)->type() == DemuxerStream::AUDIO)) {
679 continue; 612 continue;
680 } 613 }
681 (*iter)->EnqueuePacket( 614 (*iter)->EnqueuePacket(
682 scoped_ptr_malloc<AVPacket, ScopedPtrAVFreePacket>()); 615 scoped_ptr_malloc<AVPacket, ScopedPtrAVFreePacket>());
683 } 616 }
684 } 617 }
685 618
686 int FFmpegDemuxer::WaitForRead() {
687 read_event_.Wait();
688 return last_read_bytes_;
689 }
690
691 void FFmpegDemuxer::SignalReadCompleted(int size) {
692 last_read_bytes_ = size;
693 read_event_.Signal();
694 }
695
696 void FFmpegDemuxer::NotifyBufferingChanged() { 619 void FFmpegDemuxer::NotifyBufferingChanged() {
697 DCHECK(message_loop_->BelongsToCurrentThread()); 620 DCHECK(message_loop_->BelongsToCurrentThread());
698 Ranges<base::TimeDelta> buffered; 621 Ranges<base::TimeDelta> buffered;
699 scoped_refptr<FFmpegDemuxerStream> audio = 622 scoped_refptr<FFmpegDemuxerStream> audio =
700 audio_disabled_ ? NULL : GetFFmpegStream(DemuxerStream::AUDIO); 623 audio_disabled_ ? NULL : GetFFmpegStream(DemuxerStream::AUDIO);
701 scoped_refptr<FFmpegDemuxerStream> video = 624 scoped_refptr<FFmpegDemuxerStream> video =
702 GetFFmpegStream(DemuxerStream::VIDEO); 625 GetFFmpegStream(DemuxerStream::VIDEO);
703 if (audio && video) { 626 if (audio && video) {
704 buffered = audio->GetBufferedRanges().IntersectionWith( 627 buffered = audio->GetBufferedRanges().IntersectionWith(
705 video->GetBufferedRanges()); 628 video->GetBufferedRanges());
706 } else if (audio) { 629 } else if (audio) {
707 buffered = audio->GetBufferedRanges(); 630 buffered = audio->GetBufferedRanges();
708 } else if (video) { 631 } else if (video) {
709 buffered = video->GetBufferedRanges(); 632 buffered = video->GetBufferedRanges();
710 } 633 }
711 for (size_t i = 0; i < buffered.size(); ++i) 634 for (size_t i = 0; i < buffered.size(); ++i)
712 host_->AddBufferedTimeRange(buffered.start(i), buffered.end(i)); 635 host_->AddBufferedTimeRange(buffered.start(i), buffered.end(i));
713 } 636 }
714 637
638 void FFmpegDemuxer::OnDataSourceError() {
639 host_->OnDemuxerError(PIPELINE_ERROR_READ);
640 }
641
715 } // namespace media 642 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698