diff options
author | jiesun@google.com <jiesun@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-17 16:07:36 +0000 |
---|---|---|
committer | jiesun@google.com <jiesun@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-17 16:07:36 +0000 |
commit | e9a7fe502718d74531d6d1d31be83339f1757ded (patch) | |
tree | 15487c63e6387007c3da65fe9690c6db09e95b96 /chrome/gpu | |
parent | 1a03607bd3e686d79e327a714b819f56daf18586 (diff) | |
download | chromium_src-e9a7fe502718d74531d6d1d31be83339f1757ded.zip chromium_src-e9a7fe502718d74531d6d1d31be83339f1757ded.tar.gz chromium_src-e9a7fe502718d74531d6d1d31be83339f1757ded.tar.bz2 |
media: use VideoDecodeEngine interface in gpu_video_decoder abstraction.
some logics are moved into system memory path only. ( such as allocation of output buffer, and usage of FTBDoneACK messages.
Review URL: http://codereview.chromium.org/3141014
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@56358 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/gpu')
-rw-r--r-- | chrome/gpu/DEPS | 2 | ||||
-rw-r--r-- | chrome/gpu/gpu_video_decoder.cc | 223 | ||||
-rw-r--r-- | chrome/gpu/gpu_video_decoder.h | 66 | ||||
-rw-r--r-- | chrome/gpu/gpu_video_service.cc | 9 |
4 files changed, 261 insertions, 39 deletions
diff --git a/chrome/gpu/DEPS b/chrome/gpu/DEPS index f071f77..03e6502 100644 --- a/chrome/gpu/DEPS +++ b/chrome/gpu/DEPS @@ -1,5 +1,7 @@ include_rules = [
"+chrome/app",
"+gpu/command_buffer",
+ "+media/base",
+ "+media/filters",
]
diff --git a/chrome/gpu/gpu_video_decoder.cc b/chrome/gpu/gpu_video_decoder.cc index 42a7383..1a4a7f6 100644 --- a/chrome/gpu/gpu_video_decoder.cc +++ b/chrome/gpu/gpu_video_decoder.cc @@ -5,6 +5,7 @@ #include "chrome/common/gpu_messages.h" #include "chrome/gpu/gpu_channel.h" #include "chrome/gpu/gpu_video_decoder.h" +#include "media/base/data_buffer.h" void GpuVideoDecoder::OnChannelConnected(int32 peer_pid) { } @@ -30,41 +31,245 @@ void GpuVideoDecoder::OnMessageReceived(const IPC::Message& msg) { IPC_END_MESSAGE_MAP() } +bool GpuVideoDecoder::CreateInputTransferBuffer( + uint32 size, + base::SharedMemoryHandle* handle) { + input_transfer_buffer_.reset(new base::SharedMemory); + if (!input_transfer_buffer_.get()) + return false; + + if (!input_transfer_buffer_->Create(std::wstring(), false, false, size)) + return false; + + if (!input_transfer_buffer_->Map(size)) + return false; + + if (!input_transfer_buffer_->ShareToProcess(renderer_handle_, handle)) + return false; + + return true; +} + +bool GpuVideoDecoder::CreateOutputTransferBuffer( + uint32 size, + base::SharedMemoryHandle* handle) { + output_transfer_buffer_.reset(new base::SharedMemory); + if (!output_transfer_buffer_.get()) + return false; + + if (!output_transfer_buffer_->Create(std::wstring(), false, false, size)) + return false; + + if (!output_transfer_buffer_->Map(size)) + return false; + + if (!output_transfer_buffer_->ShareToProcess(renderer_handle_, handle)) + return false; + + return true; +} + +void GpuVideoDecoder::CreateVideoFrameOnTransferBuffer() { + const base::TimeDelta kZero; + uint8* data[media::VideoFrame::kMaxPlanes]; + int32 strides[media::VideoFrame::kMaxPlanes]; + memset(data, 0, sizeof(data)); + memset(strides, 0, sizeof(strides)); + data[0] = static_cast<uint8*>(output_transfer_buffer_->memory()); + data[1] = data[0] + config_.width_ * config_.height_; + data[2] = data[1] + config_.width_ * config_.height_ / 4; + strides[0] = config_.width_; + strides[1] = strides[2] = config_.width_ >> 1; + media::VideoFrame:: CreateFrameExternal( + media::VideoFrame::TYPE_SYSTEM_MEMORY, + media::VideoFrame::YV12, + config_.width_, config_.height_, 3, + data, strides, + kZero, kZero, + NULL, + &frame_); +} + +void GpuVideoDecoder::OnInitializeComplete(const VideoCodecInfo& info) { + info_ = info; + GpuVideoDecoderInitDoneParam param; + param.success_ = false; + param.input_buffer_handle_ = base::SharedMemory::NULLHandle(); + param.output_buffer_handle_ = base::SharedMemory::NULLHandle(); + + if (!info.success_) { + SendInitializeDone(param); + return; + } + + // Translate surface type. + switch (info.stream_info_.surface_type_) { + case VideoFrame::TYPE_SYSTEM_MEMORY: + param.surface_type_ = + GpuVideoDecoderInitDoneParam::SurfaceTypeSystemMemory; + break; + case VideoFrame::TYPE_DIRECT3DSURFACE: + case VideoFrame::TYPE_EGL_IMAGE: + default: + NOTREACHED(); + } + + // Translate surface format. + switch (info.stream_info_.surface_format_) { + case VideoFrame::YV12: + param.format_ = GpuVideoDecoderInitDoneParam::SurfaceFormat_YV12; + break; + default: + NOTREACHED(); + } + + // TODO(jiesun): Check the assumption of input size < original size. + param.input_buffer_size_ = config_.width_ * config_.height_ * 3 / 2; + if (!CreateInputTransferBuffer(param.input_buffer_size_, + ¶m.input_buffer_handle_)) { + SendInitializeDone(param); + return; + } + + if (info.stream_info_.surface_type_ == VideoFrame::TYPE_SYSTEM_MEMORY) { + // TODO(jiesun): Allocate this according to the surface format. + // The format actually could change during streaming, we need to + // notify GpuVideoDecoderHost side when this happened and renegotiate + // the transfer buffer. + + switch (info.stream_info_.surface_format_) { + case VideoFrame::YV12: + // TODO(jiesun): take stride into account. + param.output_buffer_size_ = + config_.width_ * config_.height_ * 3 / 2; + break; + default: + NOTREACHED(); + } + + if (!CreateOutputTransferBuffer(param.output_buffer_size_, + ¶m.output_buffer_handle_)) { + SendInitializeDone(param); + return; + } + + CreateVideoFrameOnTransferBuffer(); + } + + param.success_ = true; + + SendInitializeDone(param); +} + +void GpuVideoDecoder::OnUninitializeComplete() { + SendUninitializeDone(); +} + +void GpuVideoDecoder::OnFlushComplete() { + SendFlushDone(); +} + +void GpuVideoDecoder::OnSeekComplete() { + NOTIMPLEMENTED(); +} + +void GpuVideoDecoder::OnError() { + NOTIMPLEMENTED(); +} + +void GpuVideoDecoder::OnFormatChange(VideoStreamInfo stream_info) { + NOTIMPLEMENTED(); +} + +void GpuVideoDecoder::OnEmptyBufferCallback(scoped_refptr<Buffer> buffer) { + SendEmptyBufferDone(); +} + +void GpuVideoDecoder::OnFillBufferCallback(scoped_refptr<VideoFrame> frame) { + GpuVideoDecoderOutputBufferParam output_param; + output_param.timestamp_ = frame->GetTimestamp().InMicroseconds(); + output_param.duration_ = frame->GetDuration().InMicroseconds(); + output_param.flags_ = frame->IsEndOfStream() ? + GpuVideoDecoderOutputBufferParam::kFlagsEndOfStream : 0; + SendFillBufferDone(output_param); +} + GpuVideoDecoder::GpuVideoDecoder( const GpuVideoDecoderInfoParam* param, GpuChannel* channel, base::ProcessHandle handle) : decoder_host_route_id_(param->decoder_host_route_id_), + output_transfer_buffer_busy_(false), + pending_output_requests_(0), channel_(channel), renderer_handle_(handle) { - memset(&init_param_, 0, sizeof(init_param_)); - memset(&done_param_, 0, sizeof(done_param_)); + memset(&config_, 0, sizeof(config_)); + memset(&info_, 0, sizeof(info_)); +#if defined(OS_WIN) && defined(ENABLE_GPU_DECODER) + // TODO(jiesun): find a better way to determine which GpuVideoDecoder + // to return on current platform. + decode_engine_.reset(new GpuVideoDecoderMFT()); +#else +#endif } void GpuVideoDecoder::OnInitialize(const GpuVideoDecoderInitParam& param) { - init_param_ = param; - done_param_.success_ = DoInitialize(init_param_, &done_param_); + // TODO(jiesun): codec id should come from |param|. + config_.codec_ = media::kCodecH264; + config_.width_ = param.width_; + config_.height_ = param.height_; + config_.opaque_context_ = NULL; + decode_engine_->Initialize(NULL, this, config_); } void GpuVideoDecoder::OnUninitialize() { - DoUninitialize(); + decode_engine_->Uninitialize(); } void GpuVideoDecoder::OnFlush() { - DoFlush(); + // TODO(jiesun): this is wrong?? + output_transfer_buffer_busy_ = false; + pending_output_requests_ = 0; + + decode_engine_->Flush(); } void GpuVideoDecoder::OnEmptyThisBuffer( const GpuVideoDecoderInputBufferParam& buffer) { - DoEmptyThisBuffer(buffer); + DCHECK(input_transfer_buffer_->memory()); + + uint8* src = static_cast<uint8*>(input_transfer_buffer_->memory()); + + scoped_refptr<Buffer> input_buffer; + uint8* dst = buffer.size_ ? new uint8[buffer.size_] : NULL; + input_buffer = new media::DataBuffer(dst, buffer.size_); + memcpy(dst, src, buffer.size_); + SendEmptyBufferACK(); + + decode_engine_->EmptyThisBuffer(input_buffer); } void GpuVideoDecoder::OnFillThisBuffer( const GpuVideoDecoderOutputBufferParam& frame) { - DoFillThisBuffer(frame); + if (info_.stream_info_.surface_type_ == VideoFrame::TYPE_SYSTEM_MEMORY) { + pending_output_requests_++; + if (!output_transfer_buffer_busy_) { + output_transfer_buffer_busy_ = true; + decode_engine_->FillThisBuffer(frame_); + } + } else { + decode_engine_->FillThisBuffer(frame_); + } } void GpuVideoDecoder::OnFillThisBufferDoneACK() { - DoFillThisBufferDoneACK(); + if (info_.stream_info_.surface_type_ == VideoFrame::TYPE_SYSTEM_MEMORY) { + output_transfer_buffer_busy_ = false; + pending_output_requests_--; + if (pending_output_requests_) { + output_transfer_buffer_busy_ = true; + decode_engine_->FillThisBuffer(frame_); + } + } } void GpuVideoDecoder::SendInitializeDone( diff --git a/chrome/gpu/gpu_video_decoder.h b/chrome/gpu/gpu_video_decoder.h index 62170fe..caed871 100644 --- a/chrome/gpu/gpu_video_decoder.h +++ b/chrome/gpu/gpu_video_decoder.h @@ -10,13 +10,21 @@ #include "base/ref_counted.h" #include "base/scoped_ptr.h" #include "chrome/common/gpu_video_common.h" +#include "media/filters/video_decode_engine.h" #include "ipc/ipc_channel.h" class GpuChannel; +using media::VideoCodecConfig; +using media::VideoCodecInfo; +using media::VideoStreamInfo; +using media::VideoFrame; +using media::Buffer; + class GpuVideoDecoder : public IPC::Channel::Listener, - public base::RefCountedThreadSafe<GpuVideoDecoder> { + public base::RefCountedThreadSafe<GpuVideoDecoder>, + public media::VideoDecodeEngine::EventHandler { public: // IPC::Channel::Listener. @@ -24,43 +32,47 @@ class GpuVideoDecoder virtual void OnChannelError(); virtual void OnMessageReceived(const IPC::Message& message); - virtual bool DoInitialize(const GpuVideoDecoderInitParam& init_param, - GpuVideoDecoderInitDoneParam* done_param) = 0; - virtual bool DoUninitialize() = 0; - virtual void DoFlush() = 0; - virtual void DoEmptyThisBuffer( - const GpuVideoDecoderInputBufferParam& buffer) = 0; - virtual void DoFillThisBuffer( - const GpuVideoDecoderOutputBufferParam& frame) = 0; - virtual void DoFillThisBufferDoneACK() = 0; + // VideoDecodeEngine::EventHandler. + virtual void OnInitializeComplete(const VideoCodecInfo& info); + virtual void OnUninitializeComplete(); + virtual void OnFlushComplete(); + virtual void OnSeekComplete(); + virtual void OnError(); + virtual void OnFormatChange(VideoStreamInfo stream_info); + virtual void OnEmptyBufferCallback(scoped_refptr<Buffer> buffer); + virtual void OnFillBufferCallback(scoped_refptr<VideoFrame> frame); GpuVideoDecoder(const GpuVideoDecoderInfoParam* param, GpuChannel* channel_, base::ProcessHandle handle); virtual ~GpuVideoDecoder() {} - protected: - // Output message helper. - void SendInitializeDone(const GpuVideoDecoderInitDoneParam& param); - void SendUninitializeDone(); - void SendFlushDone(); - void SendEmptyBufferDone(); - void SendEmptyBufferACK(); - void SendFillBufferDone(const GpuVideoDecoderOutputBufferParam& frame); - + private: int32 route_id() { return decoder_host_route_id_; } + bool CreateInputTransferBuffer(uint32 size, + base::SharedMemoryHandle* handle); + bool CreateOutputTransferBuffer(uint32 size, + base::SharedMemoryHandle* handle); + void CreateVideoFrameOnTransferBuffer(); + int32 decoder_host_route_id_; + + // Used only in system memory path. i.e. Remove this later. + scoped_refptr<VideoFrame> frame_; + bool output_transfer_buffer_busy_; + int32 pending_output_requests_; + GpuChannel* channel_; base::ProcessHandle renderer_handle_; - GpuVideoDecoderInitParam init_param_; - GpuVideoDecoderInitDoneParam done_param_; - scoped_ptr<base::SharedMemory> input_transfer_buffer_; scoped_ptr<base::SharedMemory> output_transfer_buffer_; - private: + scoped_ptr<media::VideoDecodeEngine> decode_engine_; + media::VideoCodecConfig config_; + media::VideoCodecInfo info_; + // Input message handler. void OnInitialize(const GpuVideoDecoderInitParam& param); void OnUninitialize(); @@ -69,6 +81,14 @@ class GpuVideoDecoder void OnFillThisBuffer(const GpuVideoDecoderOutputBufferParam& frame); void OnFillThisBufferDoneACK(); + // Output message helper. + void SendInitializeDone(const GpuVideoDecoderInitDoneParam& param); + void SendUninitializeDone(); + void SendFlushDone(); + void SendEmptyBufferDone(); + void SendEmptyBufferACK(); + void SendFillBufferDone(const GpuVideoDecoderOutputBufferParam& frame); + DISALLOW_COPY_AND_ASSIGN(GpuVideoDecoder); }; diff --git a/chrome/gpu/gpu_video_service.cc b/chrome/gpu/gpu_video_service.cc index 78b95fd..bc95936 100644 --- a/chrome/gpu/gpu_video_service.cc +++ b/chrome/gpu/gpu_video_service.cc @@ -4,6 +4,7 @@ #include "chrome/common/gpu_messages.h" #include "chrome/gpu/gpu_channel.h" +#include "chrome/gpu/gpu_video_decoder.h" #include "chrome/gpu/gpu_video_service.h" GpuVideoService::GpuVideoService() : next_available_decoder_id_(0) { @@ -43,22 +44,16 @@ bool GpuVideoService::CreateVideoDecoder( GpuChannel* channel, MessageRouter* router, GpuVideoDecoderInfoParam* param) { - // TODO(jiesun): find a better way to determine which GpuVideoDecoder - // to return on current platform. -#if defined(ENABLE_MFT_DECODER) GpuVideoDecoderInfo decoder_info; int32 decoder_id = GetNextAvailableDecoderID(); param->decoder_id_ = decoder_id; base::ProcessHandle handle = channel->renderer_handle(); - decoder_info.decoder_ = new GpuVideoDecoderMFT(param, channel, handle); + decoder_info.decoder_ = new GpuVideoDecoder(param, channel, handle); decoder_info.channel_ = channel; decoder_info.param = *param; decoder_map_[decoder_id] = decoder_info; router->AddRoute(param->decoder_route_id_, decoder_info.decoder_); return true; -#else - return false; -#endif } void GpuVideoService::DestroyVideoDecoder( |