diff options
author | penghuang@chromium.org <penghuang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-16 05:49:50 +0000 |
---|---|---|
committer | penghuang@chromium.org <penghuang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-16 05:49:50 +0000 |
commit | 03bf382f1176290e2eae07034aa6b497670d261f (patch) | |
tree | 7f935b56c7b1143105dad9e4bbcac165a5fb2bf8 /content/renderer | |
parent | 69f4a6dc4ea415bc99fd888dcec7fc5305e9b8d3 (diff) | |
download | chromium_src-03bf382f1176290e2eae07034aa6b497670d261f.zip chromium_src-03bf382f1176290e2eae07034aa6b497670d261f.tar.gz chromium_src-03bf382f1176290e2eae07034aa6b497670d261f.tar.bz2 |
[PPAPI] Implement media stream video track API
BUG=330851
Review URL: https://codereview.chromium.org/128683003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@245150 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/renderer')
5 files changed, 399 insertions, 5 deletions
diff --git a/content/renderer/pepper/pepper_media_stream_track_host_base.cc b/content/renderer/pepper/pepper_media_stream_track_host_base.cc new file mode 100644 index 0000000..f1b4e4b --- /dev/null +++ b/content/renderer/pepper/pepper_media_stream_track_host_base.cc @@ -0,0 +1,102 @@ +// Copyright 2014 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 "content/renderer/pepper/pepper_media_stream_track_host_base.h" + +#include "base/logging.h" +#include "content/public/renderer/render_thread.h" +#include "content/public/renderer/renderer_ppapi_host.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/host/dispatch_host_message.h" +#include "ppapi/host/host_message_context.h" +#include "ppapi/host/ppapi_host.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/media_stream_frame.h" + +using ppapi::host::HostMessageContext; +using ppapi::proxy::SerializedHandle; + +namespace content { + +PepperMediaStreamTrackHostBase::PepperMediaStreamTrackHostBase( + RendererPpapiHost* host, + PP_Instance instance, + PP_Resource resource) + : ResourceHost(host->GetPpapiHost(), instance, resource), + host_(host), + frame_buffer_(this) { +} + +PepperMediaStreamTrackHostBase::~PepperMediaStreamTrackHostBase() { +} + +bool PepperMediaStreamTrackHostBase::InitFrames(int32_t number_of_frames, + int32_t frame_size) { + DCHECK_GT(number_of_frames, 0); + DCHECK_GT(frame_size, + static_cast<int32_t>(sizeof(ppapi::MediaStreamFrame::Header))); + // Make each frame 4 byte aligned. + frame_size = (frame_size + 3) & ~0x3; + + int32_t size = number_of_frames * frame_size; + content::RenderThread* render_thread = content::RenderThread::Get(); + scoped_ptr<base::SharedMemory> shm( + render_thread->HostAllocateSharedMemoryBuffer(size).Pass()); + if (!shm) + return false; + + base::SharedMemoryHandle shm_handle = shm->handle(); + if (!frame_buffer_.SetFrames(number_of_frames, frame_size, shm.Pass(), true)) + return false; + + base::PlatformFile platform_file = +#if defined(OS_WIN) + shm_handle; +#elif defined(OS_POSIX) + shm_handle.fd; +#else +#error Not implemented. +#endif + SerializedHandle handle( + host_->ShareHandleWithRemote(platform_file, false), size); + host()->SendUnsolicitedReplyWithHandles(pp_resource(), + PpapiPluginMsg_MediaStreamTrack_InitFrames(number_of_frames, frame_size), + std::vector<SerializedHandle>(1, handle)); + return true; +} + +void PepperMediaStreamTrackHostBase::SendEnqueueFrameMessageToPlugin( + int32_t index) { + DCHECK_GE(index, 0); + DCHECK_LT(index, frame_buffer_.number_of_frames()); + host()->SendUnsolicitedReply(pp_resource(), + PpapiPluginMsg_MediaStreamTrack_EnqueueFrame(index)); +} + +int32_t PepperMediaStreamTrackHostBase::OnResourceMessageReceived( + const IPC::Message& msg, + HostMessageContext* context) { + IPC_BEGIN_MESSAGE_MAP(PepperMediaStreamTrackHostBase, msg) + PPAPI_DISPATCH_HOST_RESOURCE_CALL( + PpapiHostMsg_MediaStreamTrack_EnqueueFrame, OnHostMsgEnqueueFrame) + PPAPI_DISPATCH_HOST_RESOURCE_CALL_0( + PpapiHostMsg_MediaStreamTrack_Close, OnHostMsgClose) + IPC_END_MESSAGE_MAP() + return ppapi::host::ResourceHost::OnResourceMessageReceived(msg, context); +} + +int32_t PepperMediaStreamTrackHostBase::OnHostMsgEnqueueFrame( + HostMessageContext* context, + int32_t index) { + frame_buffer_.EnqueueFrame(index); + return PP_OK; +} + +int32_t PepperMediaStreamTrackHostBase::OnHostMsgClose( + HostMessageContext* context) { + OnClose(); + return PP_OK; +} + +} // namespace content diff --git a/content/renderer/pepper/pepper_media_stream_track_host_base.h b/content/renderer/pepper/pepper_media_stream_track_host_base.h new file mode 100644 index 0000000..bb34eb5 --- /dev/null +++ b/content/renderer/pepper/pepper_media_stream_track_host_base.h @@ -0,0 +1,58 @@ +// Copyright 2014 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. + +#ifndef CONTENT_RENDERER_PEPPER_PEPPER_MEDIA_STREAM_TRACK_HOST_BASE_H_ +#define CONTENT_RENDERER_PEPPER_PEPPER_MEDIA_STREAM_TRACK_HOST_BASE_H_ + +#include "base/compiler_specific.h" +#include "content/common/content_export.h" +#include "ppapi/host/resource_host.h" +#include "ppapi/shared_impl/media_stream_frame_buffer.h" + +namespace content { + +class RendererPpapiHost; + +class PepperMediaStreamTrackHostBase + : public ppapi::host::ResourceHost, + public ppapi::MediaStreamFrameBuffer::Delegate { + protected: + PepperMediaStreamTrackHostBase(RendererPpapiHost* host, + PP_Instance instance, + PP_Resource resource); + virtual ~PepperMediaStreamTrackHostBase(); + + bool InitFrames(int32_t number_of_frames, int32_t frame_size); + + ppapi::MediaStreamFrameBuffer* frame_buffer() { return &frame_buffer_; } + + // Sends a frame index to the corresponding MediaStreamTrackResourceBase + // via an IPC message. The resource adds the frame index into its + // |frame_buffer_| for reading or writing. Also see |MediaStreamFrameBuffer|. + void SendEnqueueFrameMessageToPlugin(int32_t index); + + private: + // Subclasses must implement this method to clean up when the track is closed. + virtual void OnClose() = 0; + + // ResourceMessageHandler overrides: + virtual int32_t OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) OVERRIDE; + + // Message handlers: + int32_t OnHostMsgEnqueueFrame(ppapi::host::HostMessageContext* context, + int32_t index); + int32_t OnHostMsgClose(ppapi::host::HostMessageContext* context); + + RendererPpapiHost* host_; + + ppapi::MediaStreamFrameBuffer frame_buffer_; + + DISALLOW_COPY_AND_ASSIGN(PepperMediaStreamTrackHostBase); +}; + +} // namespace content + +#endif // CONTENT_RENDERER_PEPPER_PEPPER_MEDIA_STREAM_TRACK_HOST_BASE_H_ diff --git a/content/renderer/pepper/pepper_media_stream_video_track_host.cc b/content/renderer/pepper/pepper_media_stream_video_track_host.cc new file mode 100644 index 0000000..8996ef6 --- /dev/null +++ b/content/renderer/pepper/pepper_media_stream_video_track_host.cc @@ -0,0 +1,128 @@ +// Copyright 2014 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 "content/renderer/pepper/pepper_media_stream_video_track_host.h" + +#include "base/logging.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/ppb_video_frame.h" +#include "ppapi/shared_impl/media_stream_frame.h" + +using media::VideoFrame; + +namespace { + +// TODO(penghuang): make it configurable. +const int32_t kNumberOfFrames = 4; + +PP_VideoFrame_Format ToPpapiFormat(VideoFrame::Format format) { + switch (format) { + case VideoFrame::YV12: + return PP_VIDEOFRAME_FORMAT_YV12; + case VideoFrame::YV16: + return PP_VIDEOFRAME_FORMAT_YV16; + case VideoFrame::I420: + return PP_VIDEOFRAME_FORMAT_I420; + case VideoFrame::YV12A: + return PP_VIDEOFRAME_FORMAT_YV12A; + case VideoFrame::YV12J: + return PP_VIDEOFRAME_FORMAT_YV12J; + default: + DVLOG(1) << "Unsupported pixel format " << format; + return PP_VIDEOFRAME_FORMAT_UNKNOWN; + } +} + +} // namespace + +namespace content { + +PepperMediaStreamVideoTrackHost::PepperMediaStreamVideoTrackHost( + RendererPpapiHost* host, + PP_Instance instance, + PP_Resource resource, + const blink::WebMediaStreamTrack& track) + : PepperMediaStreamTrackHostBase(host, instance, resource), + track_(track), + connected_(false), + frame_format_(VideoFrame::UNKNOWN), + frame_data_size_(0) { + DCHECK(!track_.isNull()); +} + +PepperMediaStreamVideoTrackHost::~PepperMediaStreamVideoTrackHost() { + OnClose(); +} + +void PepperMediaStreamVideoTrackHost::OnClose() { + if (connected_) { + MediaStreamVideoSink::RemoveFromVideoTrack(this, track_); + connected_ = false; + } +} + +void PepperMediaStreamVideoTrackHost::OnVideoFrame( + const scoped_refptr<VideoFrame>& frame) { + DCHECK(frame); + // TODO(penghuang): Check |frame->end_of_stream()| and close the track. + PP_VideoFrame_Format ppformat = ToPpapiFormat(frame->format()); + if (ppformat == PP_VIDEOFRAME_FORMAT_UNKNOWN) + return; + + if (frame_size_ != frame->coded_size() || frame_format_ != frame->format()) { + frame_size_ = frame->coded_size(); + frame_format_ = frame->format(); + // TODO(penghuang): Support changing |frame_size_| & |frame_format_| more + // than once. + DCHECK(!frame_data_size_); + frame_data_size_ = VideoFrame::AllocationSize(frame_format_, frame_size_); + int32_t size = sizeof(ppapi::MediaStreamFrame::Video) + frame_data_size_; + InitFrames(kNumberOfFrames, size); + } + + int32_t index = frame_buffer()->DequeueFrame(); + // Drop frames if the underlying buffer is full. + if (index < 0) + return; + + // TODO(penghuang): support format conversion and size scaling. + ppapi::MediaStreamFrame::Video* ppframe = + &(frame_buffer()->GetFramePointer(index)->video); + ppframe->header.size = frame_buffer()->frame_size(); + ppframe->header.type = ppapi::MediaStreamFrame::TYPE_VIDEO; + ppframe->timestamp = frame->GetTimestamp().InSecondsF(); + ppframe->format = ppformat; + ppframe->size.width = frame->coded_size().width(); + ppframe->size.height = frame->coded_size().height(); + ppframe->data_size = frame_data_size_; + + COMPILE_ASSERT(VideoFrame::kYPlane == 0, y_plane_should_be_0); + COMPILE_ASSERT(VideoFrame::kUPlane == 1, u_plane_should_be_1); + COMPILE_ASSERT(VideoFrame::kVPlane == 2, v_plane_should_be_2); + + uint8_t* dst = ppframe->data; + size_t num_planes = VideoFrame::NumPlanes(frame->format()); + for (size_t i = 0; i < num_planes; ++i) { + const uint8_t* src = frame->data(i); + const size_t row_bytes = frame->row_bytes(i); + const size_t src_stride = frame->stride(i); + int rows = frame->rows(i); + for (int j = 0; j < rows; ++j) { + memcpy(dst, src, row_bytes); + dst += row_bytes; + src += src_stride; + } + } + + SendEnqueueFrameMessageToPlugin(index); +} + +void PepperMediaStreamVideoTrackHost::DidConnectPendingHostToResource() { + if (!connected_) { + MediaStreamVideoSink::AddToVideoTrack(this, track_); + connected_ = true; + } +} + +} // namespace content diff --git a/content/renderer/pepper/pepper_media_stream_video_track_host.h b/content/renderer/pepper/pepper_media_stream_video_track_host.h new file mode 100644 index 0000000..588c7eda --- /dev/null +++ b/content/renderer/pepper/pepper_media_stream_video_track_host.h @@ -0,0 +1,57 @@ +// Copyright 2014 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. + +#ifndef CONTENT_RENDERER_PEPPER_PEPPER_MEDIA_STREAM_VIDEO_TRACK_HOST_H_ +#define CONTENT_RENDERER_PEPPER_PEPPER_MEDIA_STREAM_VIDEO_TRACK_HOST_H_ + +#include "base/compiler_specific.h" +#include "content/public/renderer/media_stream_video_sink.h" +#include "content/renderer/pepper/pepper_media_stream_track_host_base.h" +#include "media/base/video_frame.h" +#include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" +#include "ui/gfx/size.h" + +namespace content { + +class PepperMediaStreamVideoTrackHost : public PepperMediaStreamTrackHostBase, + public MediaStreamVideoSink { + public: + PepperMediaStreamVideoTrackHost(RendererPpapiHost* host, + PP_Instance instance, + PP_Resource resource, + const blink::WebMediaStreamTrack& track); + + private: + virtual ~PepperMediaStreamVideoTrackHost(); + + // PepperMediaStreamTrackHostBase overrides: + virtual void OnClose() OVERRIDE; + + // MediaStreamVideoSink overrides: + virtual void OnVideoFrame( + const scoped_refptr<media::VideoFrame>& frame) OVERRIDE; + + // ResourceHost overrides: + virtual void DidConnectPendingHostToResource() OVERRIDE; + + blink::WebMediaStreamTrack track_; + + // True if it has been added to |blink::WebMediaStreamTrack| as a sink. + bool connected_; + + // Frame size. + gfx::Size frame_size_; + + // Frame format. + media::VideoFrame::Format frame_format_; + + // The size of frame pixels in bytes. + uint32_t frame_data_size_; + + DISALLOW_COPY_AND_ASSIGN(PepperMediaStreamVideoTrackHost); +}; + +} // namespace content + +#endif // CONTENT_RENDERER_PEPPER_PEPPER_MEDIA_STREAM_VIDEO_TRACK_HOST_H_ diff --git a/content/renderer/pepper/resource_converter.cc b/content/renderer/pepper/resource_converter.cc index 5054c2d..01c2117 100644 --- a/content/renderer/pepper/resource_converter.cc +++ b/content/renderer/pepper/resource_converter.cc @@ -8,6 +8,7 @@ #include "base/message_loop/message_loop.h" #include "content/public/renderer/renderer_ppapi_host.h" #include "content/renderer/pepper/pepper_file_system_host.h" +#include "content/renderer/pepper/pepper_media_stream_video_track_host.h" #include "ipc/ipc_message.h" #include "ppapi/host/ppapi_host.h" #include "ppapi/host/resource_host.h" @@ -15,8 +16,11 @@ #include "ppapi/shared_impl/resource_var.h" #include "ppapi/shared_impl/scoped_pp_var.h" #include "third_party/WebKit/public/platform/WebFileSystem.h" +#include "third_party/WebKit/public/platform/WebMediaStreamSource.h" #include "third_party/WebKit/public/web/WebDOMFileSystem.h" +#include "third_party/WebKit/public/web/WebDOMMediaStreamTrack.h" +namespace content { namespace { void FlushComplete( @@ -52,7 +56,7 @@ PP_FileSystemType WebFileSystemTypeToPPAPI(blink::WebFileSystem::Type type) { // On error, false. bool DOMFileSystemToResource( PP_Instance instance, - content::RendererPpapiHost* host, + RendererPpapiHost* host, const blink::WebDOMFileSystem& dom_file_system, int* pending_renderer_id, scoped_ptr<IPC::Message>* create_message, @@ -71,8 +75,8 @@ bool DOMFileSystemToResource( *pending_renderer_id = host->GetPpapiHost()->AddPendingResourceHost( scoped_ptr<ppapi::host::ResourceHost>( - new content::PepperFileSystemHost(host, instance, 0, root_url, - file_system_type))); + new PepperFileSystemHost(host, instance, 0, root_url, + file_system_type))); if (*pending_renderer_id == 0) return false; @@ -85,9 +89,37 @@ bool DOMFileSystemToResource( return true; } -} // namespace +bool DOMMediaStreamTrackToResource( + PP_Instance instance, + RendererPpapiHost* host, + const blink::WebDOMMediaStreamTrack& dom_media_stream_track, + int* pending_renderer_id, + scoped_ptr<IPC::Message>* create_message) { + DCHECK(!dom_media_stream_track.isNull()); + *pending_renderer_id = 0; + + const blink::WebMediaStreamTrack track = dom_media_stream_track.component(); + const std::string id = track.source().id().utf8(); + + if (track.source().type() == blink::WebMediaStreamSource::TypeVideo) { + *pending_renderer_id = host->GetPpapiHost()->AddPendingResourceHost( + scoped_ptr<ppapi::host::ResourceHost>( + new PepperMediaStreamVideoTrackHost(host, instance, 0, track))); + if (*pending_renderer_id == 0) + return false; -namespace content { + create_message->reset( + new PpapiPluginMsg_MediaStreamVideoTrack_CreateFromPendingHost(id)); + return true; + } else if (track.source().type() == blink::WebMediaStreamSource::TypeAudio) { + // TODO(penghuang): support audio track. + return false; + } + + return false; +} + +} // namespace ResourceConverter::~ResourceConverter() {} @@ -133,6 +165,23 @@ bool ResourceConverterImpl::FromV8Value(v8::Handle<v8::Object> val, return true; } + blink::WebDOMMediaStreamTrack dom_media_stream_track = + blink::WebDOMMediaStreamTrack::fromV8Value(val); + if (!dom_media_stream_track.isNull()) { + int pending_renderer_id; + scoped_ptr<IPC::Message> create_message; + if (!DOMMediaStreamTrackToResource(instance_, host_, dom_media_stream_track, + &pending_renderer_id, &create_message)) { + return false; + } + DCHECK(create_message); + scoped_refptr<HostResourceVar> result_var = CreateResourceVar( + pending_renderer_id, *create_message); + *result = result_var->GetPPVar(); + *was_resource = true; + return true; + } + // The value was not convertible to a resource. Return true with // |was_resource| set to false. As per the interface of FromV8Value, |result| // may be left unmodified in this case. |