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
27 namespace {
28
29 // Helper functions
SplitStringBySpace(const std::string & str)30 std::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.
39 class VEDemoModule : public pp::Module {
40 public:
VEDemoModule()41 VEDemoModule() : pp::Module() {}
~VEDemoModule()42 virtual ~VEDemoModule() {}
43
44 virtual pp::Instance* CreateInstance(PP_Instance instance);
45 };
46
47 class 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
VEDemoInstance(PP_Instance instance,pp::Module * module)67 VEDemoInstance::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
~VEDemoInstance()76 VEDemoInstance::~VEDemoInstance() {
77 video_source_.Close();
78 video_destination_.Close();
79 }
80
HandleMessage(const pp::Var & message_data)81 void 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
DestinationOpenDone(int32_t result,const std::string & src_url)109 void 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
SourceOpenDone(int32_t result)120 void 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
GetFrameDone(int32_t result,pp::VideoFrame_Private video_frame)132 void 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
KickoffEffect(int32_t)161 void 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
CreateInstance(PP_Instance instance)168 pp::Instance* VEDemoModule::CreateInstance(PP_Instance instance) {
169 return new VEDemoInstance(instance, this);
170 }
171
172 } // anonymous namespace
173
174 namespace pp {
175 // Factory function for your specialization of the Module object.
CreateModule()176 Module* CreateModule() {
177 return new VEDemoModule();
178 }
179 } // namespace pp
180