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 <string.h>
6#include <iterator>
7#include <sstream>
8#include <string>
9#include <vector>
10
11#include "ppapi/c/pp_errors.h"
12#include "ppapi/cpp/instance.h"
13#include "ppapi/cpp/message_loop.h"
14#include "ppapi/cpp/module.h"
15#include "ppapi/cpp/private/video_destination_private.h"
16#include "ppapi/cpp/private/video_frame_private.h"
17#include "ppapi/cpp/private/video_source_private.h"
18#include "ppapi/cpp/var.h"
19#include "ppapi/utility/completion_callback_factory.h"
20
21// When compiling natively on Windows, PostMessage can be #define-d to
22// something else.
23#ifdef PostMessage
24#undef PostMessage
25#endif
26
27namespace {
28
29// Helper functions
30std::vector<std::string> SplitStringBySpace(const std::string& str) {
31  std::istringstream buf(str);
32  std::istream_iterator<std::string> begin(buf), end;
33  std::vector<std::string> tokens(begin, end);
34  return tokens;
35}
36
37// This object is the global object representing this plugin library as long
38// as it is loaded.
39class VEDemoModule : public pp::Module {
40 public:
41  VEDemoModule() : pp::Module() {}
42  virtual ~VEDemoModule() {}
43
44  virtual pp::Instance* CreateInstance(PP_Instance instance);
45};
46
47class VEDemoInstance : public pp::Instance {
48 public:
49  VEDemoInstance(PP_Instance instance, pp::Module* module);
50  virtual ~VEDemoInstance();
51
52  // pp::Instance implementation (see PPP_Instance).
53  virtual void HandleMessage(const pp::Var& message_data);
54
55 private:
56  void DestinationOpenDone(int32_t result, const std::string& src_url);
57  void SourceOpenDone(int32_t result);
58  void GetFrameDone(int32_t result, pp::VideoFrame_Private video_frame);
59  void KickoffEffect(int32_t result);
60  pp::VideoSource_Private video_source_;
61  pp::VideoDestination_Private video_destination_;
62  bool effect_on_;
63  pp::CompletionCallbackFactory<VEDemoInstance> factory_;
64  pp::MessageLoop message_loop_;
65};
66
67VEDemoInstance::VEDemoInstance(PP_Instance instance, pp::Module* module)
68    : pp::Instance(instance),
69      video_source_(this),
70      video_destination_(this),
71      effect_on_(false),
72      message_loop_(pp::MessageLoop::GetCurrent()) {
73  factory_.Initialize(this);
74}
75
76VEDemoInstance::~VEDemoInstance() {
77  video_source_.Close();
78  video_destination_.Close();
79}
80
81void VEDemoInstance::HandleMessage(const pp::Var& message_data) {
82  if (message_data.is_string()) {
83    std::vector<std::string> messages;
84    messages = SplitStringBySpace(message_data.AsString());
85    if (messages.empty()) {
86      PostMessage(pp::Var("Ignored empty message."));
87      return;
88    }
89    if (messages[0] == "registerStream") {
90      if (messages.size() < 3) {
91        PostMessage(pp::Var("Got 'registerStream' with incorrect parameters."));
92        return;
93      }
94      // Open destination stream for write.
95      video_destination_.Open(
96          messages[2],
97          factory_.NewCallback(&VEDemoInstance::DestinationOpenDone,
98                               messages[1]));
99    } else if (messages[0] == "effectOn") {
100      effect_on_ = true;
101      PostMessage(pp::Var("Effect ON."));
102    } else if (messages[0] == "effectOff") {
103      effect_on_ = false;
104      PostMessage(pp::Var("Effect OFF."));
105    }
106  }
107}
108
109void VEDemoInstance::DestinationOpenDone(int32_t result,
110                                         const std::string& src_url) {
111  if (result != PP_OK) {
112    PostMessage(pp::Var("Failed to open destination stream."));
113    return;
114  }
115  // Open source stream for read.
116  video_source_.Open(src_url,
117                     factory_.NewCallback(&VEDemoInstance::SourceOpenDone));
118}
119
120void VEDemoInstance::SourceOpenDone(int32_t result) {
121  if (result != PP_OK) {
122    PostMessage(pp::Var("Failed to open source stream."));
123    return;
124  }
125  // Done with the stream register.
126  PostMessage(pp::Var("DoneRegistering"));
127
128  // Kick off the processing loop.
129  message_loop_.PostWork(factory_.NewCallback(&VEDemoInstance::KickoffEffect));
130}
131
132void VEDemoInstance::GetFrameDone(int32_t result,
133                                  pp::VideoFrame_Private video_frame) {
134  if (result != PP_OK) {
135    PostMessage(pp::Var("Failed to get frame."));
136    return;
137  }
138
139  // Apply the effect to the received frame.
140  if (effect_on_) {
141    pp::ImageData image_data = video_frame.image_data();
142    pp::Size size = image_data.size();
143    std::vector<uint8_t> tmp_row(image_data.stride());
144    uint8_t* image = static_cast<uint8_t*>(image_data.data());
145    for (int i = 0; i < size.height() / 2; ++i) {
146      uint8_t* top = image + i * image_data.stride();
147      uint8_t* bottom = image + (size.height() - 1 - i) * image_data.stride();
148      memcpy(&tmp_row[0], top, image_data.stride());
149      memcpy(top, bottom, image_data.stride());
150      memcpy(bottom, &tmp_row[0], image_data.stride());
151    }
152  }
153
154  // Put frame back to destination stream
155  video_destination_.PutFrame(video_frame);
156
157  // Trigger for the next frame.
158  message_loop_.PostWork(factory_.NewCallback(&VEDemoInstance::KickoffEffect));
159}
160
161void VEDemoInstance::KickoffEffect(int32_t /* result */) {
162  // Get the frame from the source stream.
163  video_source_.GetFrame(
164      factory_.NewCallbackWithOutput<pp::VideoFrame_Private>(
165          &VEDemoInstance::GetFrameDone));
166}
167
168pp::Instance* VEDemoModule::CreateInstance(PP_Instance instance) {
169  return new VEDemoInstance(instance, this);
170}
171
172}  // anonymous namespace
173
174namespace pp {
175// Factory function for your specialization of the Module object.
176Module* CreateModule() {
177  return new VEDemoModule();
178}
179}  // namespace pp
180