1// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/renderer/pepper/pepper_video_destination_host.h"
6
7#include "base/time/time.h"
8#include "content/public/renderer/renderer_ppapi_host.h"
9#include "content/renderer/pepper/ppb_image_data_impl.h"
10#include "ppapi/c/pp_errors.h"
11#include "ppapi/host/dispatch_host_message.h"
12#include "ppapi/host/host_message_context.h"
13#include "ppapi/host/ppapi_host.h"
14#include "ppapi/proxy/ppapi_messages.h"
15#include "ppapi/thunk/enter.h"
16#include "ppapi/thunk/ppb_image_data_api.h"
17
18using ppapi::host::HostMessageContext;
19using ppapi::host::ReplyMessageContext;
20
21namespace content {
22
23PepperVideoDestinationHost::PepperVideoDestinationHost(RendererPpapiHost* host,
24                                                       PP_Instance instance,
25                                                       PP_Resource resource)
26    : ResourceHost(host->GetPpapiHost(), instance, resource),
27      renderer_ppapi_host_(host),
28      weak_factory_(this) {}
29
30PepperVideoDestinationHost::~PepperVideoDestinationHost() {}
31
32int32_t PepperVideoDestinationHost::OnResourceMessageReceived(
33    const IPC::Message& msg,
34    HostMessageContext* context) {
35  PPAPI_BEGIN_MESSAGE_MAP(PepperVideoDestinationHost, msg)
36    PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDestination_Open,
37                                      OnHostMsgOpen)
38    PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDestination_PutFrame,
39                                      OnHostMsgPutFrame)
40    PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoDestination_Close,
41                                        OnHostMsgClose)
42  PPAPI_END_MESSAGE_MAP()
43  return PP_ERROR_FAILED;
44}
45
46int32_t PepperVideoDestinationHost::OnHostMsgOpen(
47    HostMessageContext* context,
48    const std::string& stream_url) {
49  GURL gurl(stream_url);
50  if (!gurl.is_valid())
51    return PP_ERROR_BADARGUMENT;
52
53  FrameWriterInterface* frame_writer = NULL;
54  if (!VideoDestinationHandler::Open(
55          NULL /* registry */, gurl.spec(), &frame_writer))
56    return PP_ERROR_FAILED;
57  frame_writer_.reset(frame_writer);
58
59  ReplyMessageContext reply_context = context->MakeReplyMessageContext();
60  reply_context.params.set_result(PP_OK);
61  host()->SendReply(reply_context, PpapiPluginMsg_VideoDestination_OpenReply());
62  return PP_OK_COMPLETIONPENDING;
63}
64
65int32_t PepperVideoDestinationHost::OnHostMsgPutFrame(
66    HostMessageContext* context,
67    const ppapi::HostResource& image_data_resource,
68    PP_TimeTicks timestamp) {
69  ppapi::thunk::EnterResourceNoLock<ppapi::thunk::PPB_ImageData_API> enter(
70      image_data_resource.host_resource(), true);
71  if (enter.failed())
72    return PP_ERROR_BADRESOURCE;
73  PPB_ImageData_Impl* image_data_impl =
74      static_cast<PPB_ImageData_Impl*>(enter.object());
75
76  if (!PPB_ImageData_Impl::IsImageDataFormatSupported(
77          image_data_impl->format()))
78    return PP_ERROR_BADARGUMENT;
79
80  if (!frame_writer_.get())
81    return PP_ERROR_FAILED;
82
83  // Convert PP_TimeTicks (a double, in seconds) to a TimeDelta (int64,
84  // microseconds) and then to a video timestamp (int64, nanoseconds). All times
85  // are relative to the Unix Epoch so don't subtract it to get a delta.
86  base::TimeDelta time_delta =
87      base::Time::FromDoubleT(timestamp) - base::Time();
88  int64_t timestamp_ns =
89      time_delta.InMicroseconds() * base::Time::kNanosecondsPerMicrosecond;
90  frame_writer_->PutFrame(image_data_impl, timestamp_ns);
91
92  return PP_OK;
93}
94
95int32_t PepperVideoDestinationHost::OnHostMsgClose(
96    HostMessageContext* context) {
97  frame_writer_.reset(NULL);
98  return PP_OK;
99}
100
101}  // namespace content
102