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 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: 41 VEDemoModule() : pp::Module() {} 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 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 76 VEDemoInstance::~VEDemoInstance() { 77 video_source_.Close(); 78 video_destination_.Close(); 79 } 80 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 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 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 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 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 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. 176 Module* CreateModule() { 177 return new VEDemoModule(); 178 } 179 } // namespace pp 180