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

Unified Diff: chrome/renderer/media/ipc_video_decoder.cc

Issue 2873089: media: gpu process ipc video decoder implementation (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: remove mft Created 10 years, 4 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/renderer/media/ipc_video_decoder.h ('k') | chrome/renderer/render_thread.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/renderer/media/ipc_video_decoder.cc
diff --git a/chrome/renderer/media/ipc_video_decoder.cc b/chrome/renderer/media/ipc_video_decoder.cc
new file mode 100644
index 0000000000000000000000000000000000000000..9d47260c5a2381ffc57390907f66db59c1e6e0d7
--- /dev/null
+++ b/chrome/renderer/media/ipc_video_decoder.cc
@@ -0,0 +1,344 @@
+// 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
+
« no previous file with comments | « chrome/renderer/media/ipc_video_decoder.h ('k') | chrome/renderer/render_thread.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698