summaryrefslogtreecommitdiffstats
path: root/content/renderer
diff options
context:
space:
mode:
authorpenghuang@chromium.org <penghuang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-16 05:49:50 +0000
committerpenghuang@chromium.org <penghuang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-16 05:49:50 +0000
commit03bf382f1176290e2eae07034aa6b497670d261f (patch)
tree7f935b56c7b1143105dad9e4bbcac165a5fb2bf8 /content/renderer
parent69f4a6dc4ea415bc99fd888dcec7fc5305e9b8d3 (diff)
downloadchromium_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')
-rw-r--r--content/renderer/pepper/pepper_media_stream_track_host_base.cc102
-rw-r--r--content/renderer/pepper/pepper_media_stream_track_host_base.h58
-rw-r--r--content/renderer/pepper/pepper_media_stream_video_track_host.cc128
-rw-r--r--content/renderer/pepper/pepper_media_stream_video_track_host.h57
-rw-r--r--content/renderer/pepper/resource_converter.cc59
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.