| Index: chrome/renderer/media/ipc_video_decoder.cc
|
| ===================================================================
|
| --- chrome/renderer/media/ipc_video_decoder.cc (revision 55418)
|
| +++ chrome/renderer/media/ipc_video_decoder.cc (working copy)
|
| @@ -1,344 +0,0 @@
|
| -// Copyright (c) 2010 The Chromium Authors. All rights reserved. Use of this
|
| -// source code is governed by a BSD-style license that can be found in the
|
| -// LICENSE file.
|
| -
|
| -
|
| -#include "chrome/renderer/media/ipc_video_decoder.h"
|
| -
|
| -#include "base/task.h"
|
| -#include "media/base/callback.h"
|
| -#include "media/base/filters.h"
|
| -#include "media/base/filter_host.h"
|
| -#include "media/base/limits.h"
|
| -#include "media/base/media_format.h"
|
| -#include "media/base/video_frame.h"
|
| -#include "media/ffmpeg/ffmpeg_common.h"
|
| -#include "media/ffmpeg/ffmpeg_util.h"
|
| -#include "media/filters/ffmpeg_interfaces.h"
|
| -
|
| -namespace media {
|
| -
|
| -IpcVideoDecoder::IpcVideoDecoder(MessageLoop* message_loop)
|
| - : width_(0),
|
| - height_(0),
|
| - state_(kUnInitialized),
|
| - pending_reads_(0),
|
| - pending_requests_(0),
|
| - renderer_thread_message_loop_(message_loop) {
|
| -}
|
| -
|
| -IpcVideoDecoder::~IpcVideoDecoder() {
|
| -}
|
| -
|
| -void IpcVideoDecoder::Initialize(DemuxerStream* demuxer_stream,
|
| - FilterCallback* callback) {
|
| - if (MessageLoop::current() != renderer_thread_message_loop_) {
|
| - renderer_thread_message_loop_->PostTask(
|
| - FROM_HERE,
|
| - NewRunnableMethod(this,
|
| - &IpcVideoDecoder::Initialize,
|
| - demuxer_stream,
|
| - callback));
|
| - return;
|
| - }
|
| -
|
| - CHECK(!demuxer_stream_);
|
| - demuxer_stream_ = demuxer_stream;
|
| - initialize_callback_.reset(callback);
|
| -
|
| - // Get the AVStream by querying for the provider interface.
|
| - AVStreamProvider* av_stream_provider;
|
| - if (!demuxer_stream->QueryInterface(&av_stream_provider)) {
|
| - GpuVideoDecoderInitDoneParam param;
|
| - OnInitializeDone(false, param);
|
| - return;
|
| - }
|
| -
|
| - AVStream* av_stream = av_stream_provider->GetAVStream();
|
| - width_ = av_stream->codec->width;
|
| - height_ = av_stream->codec->height;
|
| -
|
| - // Create hardware decoder instance.
|
| - GpuVideoServiceHost* gpu_video_service_host = GpuVideoServiceHost::get();
|
| - gpu_video_decoder_host_ = gpu_video_service_host->CreateVideoDecoder(this);
|
| -
|
| - // Initialize hardware decoder.
|
| - GpuVideoDecoderInitParam param;
|
| - param.width_ = width_;
|
| - param.height_ = height_;
|
| - if (!gpu_video_decoder_host_->Initialize(param)) {
|
| - GpuVideoDecoderInitDoneParam param;
|
| - OnInitializeDone(false, param);
|
| - }
|
| -}
|
| -
|
| -void IpcVideoDecoder::OnInitializeDone(
|
| - bool success, const GpuVideoDecoderInitDoneParam& param) {
|
| - if (MessageLoop::current() != renderer_thread_message_loop_) {
|
| - renderer_thread_message_loop_->PostTask(
|
| - FROM_HERE,
|
| - NewRunnableMethod(this,
|
| - &IpcVideoDecoder::OnInitializeDone,
|
| - success,
|
| - param));
|
| - return;
|
| - }
|
| -
|
| - AutoCallbackRunner done_runner(initialize_callback_.release());
|
| -
|
| - if (success) {
|
| - media_format_.SetAsString(MediaFormat::kMimeType,
|
| - mime_type::kUncompressedVideo);
|
| - media_format_.SetAsInteger(MediaFormat::kWidth, width_);
|
| - media_format_.SetAsInteger(MediaFormat::kHeight, height_);
|
| - media_format_.SetAsInteger(MediaFormat::kSurfaceType,
|
| - static_cast<int>(param.surface_type_));
|
| - media_format_.SetAsInteger(MediaFormat::kSurfaceFormat,
|
| - static_cast<int>(param.format_));
|
| - state_ = kPlaying;
|
| - } else {
|
| - LOG(ERROR) << "IpcVideoDecoder initialization failed!";
|
| - host()->SetError(PIPELINE_ERROR_DECODE);
|
| - }
|
| -}
|
| -
|
| -void IpcVideoDecoder::Stop(FilterCallback* callback) {
|
| - if (MessageLoop::current() != renderer_thread_message_loop_) {
|
| - renderer_thread_message_loop_->PostTask(
|
| - FROM_HERE,
|
| - NewRunnableMethod(this,
|
| - &IpcVideoDecoder::Stop,
|
| - callback));
|
| - return;
|
| - }
|
| -
|
| - stop_callback_.reset(callback);
|
| - if (!gpu_video_decoder_host_->Uninitialize()) {
|
| - LOG(ERROR) << "gpu video decoder destroy failed";
|
| - IpcVideoDecoder::OnUninitializeDone();
|
| - }
|
| -}
|
| -
|
| -void IpcVideoDecoder::OnUninitializeDone() {
|
| - if (MessageLoop::current() != renderer_thread_message_loop_) {
|
| - renderer_thread_message_loop_->PostTask(
|
| - FROM_HERE,
|
| - NewRunnableMethod(this,
|
| - &IpcVideoDecoder::OnUninitializeDone));
|
| - return;
|
| - }
|
| -
|
| - AutoCallbackRunner done_runner(stop_callback_.release());
|
| -
|
| - state_ = kStopped;
|
| -}
|
| -
|
| -void IpcVideoDecoder::Pause(FilterCallback* callback) {
|
| - Flush(callback); // TODO(jiesun): move this to flush().
|
| -}
|
| -
|
| -void IpcVideoDecoder::Flush(FilterCallback* callback) {
|
| - if (MessageLoop::current() != renderer_thread_message_loop_) {
|
| - renderer_thread_message_loop_->PostTask(
|
| - FROM_HERE,
|
| - NewRunnableMethod(this,
|
| - &IpcVideoDecoder::Flush,
|
| - callback));
|
| - return;
|
| - }
|
| -
|
| - state_ = kFlushing;
|
| -
|
| - flush_callback_.reset(callback);
|
| -
|
| - if (!gpu_video_decoder_host_->Flush()) {
|
| - LOG(ERROR) << "gpu video decoder flush failed";
|
| - OnFlushDone();
|
| - }
|
| -}
|
| -
|
| -void IpcVideoDecoder::OnFlushDone() {
|
| - if (MessageLoop::current() != renderer_thread_message_loop_) {
|
| - renderer_thread_message_loop_->PostTask(
|
| - FROM_HERE,
|
| - NewRunnableMethod(this,
|
| - &IpcVideoDecoder::OnFlushDone));
|
| - return;
|
| - }
|
| -
|
| - if (pending_reads_ == 0 && pending_requests_ == 0 && flush_callback_.get()) {
|
| - flush_callback_->Run();
|
| - flush_callback_.reset();
|
| - }
|
| -}
|
| -
|
| -void IpcVideoDecoder::Seek(base::TimeDelta time, FilterCallback* callback) {
|
| - if (MessageLoop::current() != renderer_thread_message_loop_) {
|
| - renderer_thread_message_loop_->PostTask(
|
| - FROM_HERE,
|
| - NewRunnableMethod(this,
|
| - &IpcVideoDecoder::Seek,
|
| - time,
|
| - callback));
|
| - return;
|
| - }
|
| -
|
| - OnSeekComplete(callback);
|
| -}
|
| -
|
| -void IpcVideoDecoder::OnSeekComplete(FilterCallback* callback) {
|
| - if (MessageLoop::current() != renderer_thread_message_loop_) {
|
| - renderer_thread_message_loop_->PostTask(
|
| - FROM_HERE,
|
| - NewRunnableMethod(this,
|
| - &IpcVideoDecoder::OnSeekComplete,
|
| - callback));
|
| - return;
|
| - }
|
| -
|
| - AutoCallbackRunner done_runner(callback);
|
| -
|
| - state_ = kPlaying;
|
| -
|
| - for (int i = 0; i < 20; ++i) {
|
| - demuxer_stream_->Read(
|
| - NewCallback(this,
|
| - &IpcVideoDecoder::OnReadComplete));
|
| - ++pending_reads_;
|
| - }
|
| -}
|
| -
|
| -void IpcVideoDecoder::OnReadComplete(Buffer* buffer) {
|
| - scoped_refptr<Buffer> buffer_ref = buffer;
|
| - ReadCompleteTask(buffer_ref);
|
| -}
|
| -
|
| -void IpcVideoDecoder::ReadCompleteTask(scoped_refptr<Buffer> buffer) {
|
| - if (MessageLoop::current() != renderer_thread_message_loop_) {
|
| - renderer_thread_message_loop_->PostTask(
|
| - FROM_HERE,
|
| - NewRunnableMethod(this,
|
| - &IpcVideoDecoder::ReadCompleteTask,
|
| - buffer));
|
| - return;
|
| - }
|
| -
|
| - DCHECK_GT(pending_reads_, 0u);
|
| - --pending_reads_;
|
| -
|
| - if (state_ == kStopped || state_ == kEnded) {
|
| - // Just discard the input buffers
|
| - return;
|
| - }
|
| -
|
| - if (state_ == kFlushing) {
|
| - if (pending_reads_ == 0 && pending_requests_ == 0) {
|
| - CHECK(flush_callback_.get());
|
| - flush_callback_->Run();
|
| - flush_callback_.reset();
|
| - state_ = kPlaying;
|
| - }
|
| - return;
|
| - }
|
| - // Transition to kFlushCodec on the first end of input stream buffer.
|
| - if (state_ == kPlaying && buffer->IsEndOfStream()) {
|
| - state_ = kFlushCodec;
|
| - }
|
| -
|
| - gpu_video_decoder_host_->EmptyThisBuffer(buffer);
|
| -}
|
| -
|
| -void IpcVideoDecoder::FillThisBuffer(scoped_refptr<VideoFrame> video_frame) {
|
| - if (MessageLoop::current() != renderer_thread_message_loop_) {
|
| - renderer_thread_message_loop_->PostTask(
|
| - FROM_HERE,
|
| - NewRunnableMethod(this,
|
| - &IpcVideoDecoder::FillThisBuffer,
|
| - video_frame));
|
| - return;
|
| - }
|
| -
|
| - // Synchronized flushing before stop should prevent this.
|
| - CHECK_NE(state_, kStopped);
|
| -
|
| - // Notify decode engine the available of new frame.
|
| - ++pending_requests_;
|
| - gpu_video_decoder_host_->FillThisBuffer(video_frame);
|
| -}
|
| -
|
| -void IpcVideoDecoder::OnFillBufferDone(scoped_refptr<VideoFrame> video_frame) {
|
| - if (MessageLoop::current() != renderer_thread_message_loop_) {
|
| - renderer_thread_message_loop_->PostTask(
|
| - FROM_HERE,
|
| - NewRunnableMethod(this,
|
| - &IpcVideoDecoder::OnFillBufferDone,
|
| - video_frame));
|
| - return;
|
| - }
|
| -
|
| - if (video_frame.get()) {
|
| - --pending_requests_;
|
| - fill_buffer_done_callback()->Run(video_frame);
|
| - if (state_ == kFlushing && pending_reads_ == 0 && pending_requests_ == 0) {
|
| - CHECK(flush_callback_.get());
|
| - flush_callback_->Run();
|
| - flush_callback_.reset();
|
| - state_ = kPlaying;
|
| - }
|
| -
|
| - } else {
|
| - if (state_ == kFlushCodec) {
|
| - // When in kFlushCodec, any errored decode, or a 0-lengthed frame,
|
| - // is taken as a signal to stop decoding.
|
| - state_ = kEnded;
|
| - scoped_refptr<VideoFrame> video_frame;
|
| - VideoFrame::CreateEmptyFrame(&video_frame);
|
| - fill_buffer_done_callback()->Run(video_frame);
|
| - }
|
| - }
|
| -}
|
| -
|
| -void IpcVideoDecoder::OnEmptyBufferDone(scoped_refptr<Buffer> buffer) {
|
| - if (MessageLoop::current() != renderer_thread_message_loop_) {
|
| - renderer_thread_message_loop_->PostTask(
|
| - FROM_HERE,
|
| - NewRunnableMethod(this,
|
| - &IpcVideoDecoder::OnEmptyBufferDone,
|
| - buffer));
|
| - return;
|
| - }
|
| -
|
| - // TODO(jiesun): We haven't recycle input buffer yet.
|
| - demuxer_stream_->Read(NewCallback(this, &IpcVideoDecoder::OnReadComplete));
|
| - ++pending_reads_;
|
| -}
|
| -
|
| -void IpcVideoDecoder::OnDeviceError() {
|
| - host()->SetError(PIPELINE_ERROR_DECODE);
|
| -}
|
| -
|
| -bool IpcVideoDecoder::ProvidesBuffer() {
|
| - return true;
|
| -}
|
| -
|
| -// static
|
| -FilterFactory* IpcVideoDecoder::CreateFactory(MessageLoop* message_loop) {
|
| - return new FilterFactoryImpl1<IpcVideoDecoder, MessageLoop*>(message_loop);
|
| -}
|
| -
|
| -// static
|
| -bool IpcVideoDecoder::IsMediaFormatSupported(const MediaFormat& format) {
|
| - std::string mime_type;
|
| - if (!format.GetAsString(MediaFormat::kMimeType, &mime_type) &&
|
| - mime_type::kFFmpegVideo != mime_type)
|
| - return false;
|
| -
|
| - // TODO(jiesun): Although we current only support H264 hardware decoding,
|
| - // in the future, we should query GpuVideoService for capabilities.
|
| - int codec_id;
|
| - return format.GetAsInteger(MediaFormat::kFFmpegCodecID, &codec_id) &&
|
| - codec_id == CODEC_ID_H264;
|
| -}
|
| -
|
| -} // namespace media
|
| -
|
|
|