| // Copyright (c) 2013 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 <string.h> |
| #include <iterator> |
| #include <sstream> |
| #include <string> |
| #include <vector> |
| |
| #include "ppapi/c/pp_errors.h" |
| #include "ppapi/cpp/instance.h" |
| #include "ppapi/cpp/message_loop.h" |
| #include "ppapi/cpp/module.h" |
| #include "ppapi/cpp/private/video_destination_private.h" |
| #include "ppapi/cpp/private/video_frame_private.h" |
| #include "ppapi/cpp/private/video_source_private.h" |
| #include "ppapi/cpp/var.h" |
| #include "ppapi/utility/completion_callback_factory.h" |
| |
| // When compiling natively on Windows, PostMessage can be #define-d to |
| // something else. |
| #ifdef PostMessage |
| #undef PostMessage |
| #endif |
| |
| namespace { |
| |
| // Helper functions |
| std::vector<std::string> SplitStringBySpace(const std::string& str) { |
| std::istringstream buf(str); |
| std::istream_iterator<std::string> begin(buf), end; |
| std::vector<std::string> tokens(begin, end); |
| return tokens; |
| } |
| |
| // This object is the global object representing this plugin library as long |
| // as it is loaded. |
| class VEDemoModule : public pp::Module { |
| public: |
| VEDemoModule() : pp::Module() {} |
| virtual ~VEDemoModule() {} |
| |
| virtual pp::Instance* CreateInstance(PP_Instance instance); |
| }; |
| |
| class VEDemoInstance : public pp::Instance { |
| public: |
| VEDemoInstance(PP_Instance instance, pp::Module* module); |
| virtual ~VEDemoInstance(); |
| |
| // pp::Instance implementation (see PPP_Instance). |
| virtual void HandleMessage(const pp::Var& message_data); |
| |
| private: |
| void DestinationOpenDone(int32_t result, const std::string& src_url); |
| void SourceOpenDone(int32_t result); |
| void GetFrameDone(int32_t result, pp::VideoFrame_Private video_frame); |
| void KickoffEffect(int32_t result); |
| pp::VideoSource_Private video_source_; |
| pp::VideoDestination_Private video_destination_; |
| bool effect_on_; |
| pp::CompletionCallbackFactory<VEDemoInstance> factory_; |
| pp::MessageLoop message_loop_; |
| }; |
| |
| VEDemoInstance::VEDemoInstance(PP_Instance instance, pp::Module* module) |
| : pp::Instance(instance), |
| video_source_(this), |
| video_destination_(this), |
| effect_on_(false), |
| message_loop_(pp::MessageLoop::GetCurrent()) { |
| factory_.Initialize(this); |
| } |
| |
| VEDemoInstance::~VEDemoInstance() { |
| video_source_.Close(); |
| video_destination_.Close(); |
| } |
| |
| void VEDemoInstance::HandleMessage(const pp::Var& message_data) { |
| if (message_data.is_string()) { |
| std::vector<std::string> messages; |
| messages = SplitStringBySpace(message_data.AsString()); |
| if (messages.empty()) { |
| PostMessage(pp::Var("Ignored empty message.")); |
| return; |
| } |
| if (messages[0] == "registerStream") { |
| if (messages.size() < 3) { |
| PostMessage(pp::Var("Got 'registerStream' with incorrect parameters.")); |
| return; |
| } |
| // Open destination stream for write. |
| video_destination_.Open( |
| messages[2], |
| factory_.NewCallback(&VEDemoInstance::DestinationOpenDone, |
| messages[1])); |
| } else if (messages[0] == "effectOn") { |
| effect_on_ = true; |
| PostMessage(pp::Var("Effect ON.")); |
| } else if (messages[0] == "effectOff") { |
| effect_on_ = false; |
| PostMessage(pp::Var("Effect OFF.")); |
| } |
| } |
| } |
| |
| void VEDemoInstance::DestinationOpenDone(int32_t result, |
| const std::string& src_url) { |
| if (result != PP_OK) { |
| PostMessage(pp::Var("Failed to open destination stream.")); |
| return; |
| } |
| // Open source stream for read. |
| video_source_.Open(src_url, |
| factory_.NewCallback(&VEDemoInstance::SourceOpenDone)); |
| } |
| |
| void VEDemoInstance::SourceOpenDone(int32_t result) { |
| if (result != PP_OK) { |
| PostMessage(pp::Var("Failed to open source stream.")); |
| return; |
| } |
| // Done with the stream register. |
| PostMessage(pp::Var("DoneRegistering")); |
| |
| // Kick off the processing loop. |
| message_loop_.PostWork(factory_.NewCallback(&VEDemoInstance::KickoffEffect)); |
| } |
| |
| void VEDemoInstance::GetFrameDone(int32_t result, |
| pp::VideoFrame_Private video_frame) { |
| if (result != PP_OK) { |
| PostMessage(pp::Var("Failed to get frame.")); |
| return; |
| } |
| |
| // Apply the effect to the received frame. |
| if (effect_on_) { |
| pp::ImageData image_data = video_frame.image_data(); |
| pp::Size size = image_data.size(); |
| std::vector<uint8_t> tmp_row(image_data.stride()); |
| uint8_t* image = static_cast<uint8_t*>(image_data.data()); |
| for (int i = 0; i < size.height() / 2; ++i) { |
| uint8_t* top = image + i * image_data.stride(); |
| uint8_t* bottom = image + (size.height() - 1 - i) * image_data.stride(); |
| memcpy(&tmp_row[0], top, image_data.stride()); |
| memcpy(top, bottom, image_data.stride()); |
| memcpy(bottom, &tmp_row[0], image_data.stride()); |
| } |
| } |
| |
| // Put frame back to destination stream |
| video_destination_.PutFrame(video_frame); |
| |
| // Trigger for the next frame. |
| message_loop_.PostWork(factory_.NewCallback(&VEDemoInstance::KickoffEffect)); |
| } |
| |
| void VEDemoInstance::KickoffEffect(int32_t /* result */) { |
| // Get the frame from the source stream. |
| video_source_.GetFrame( |
| factory_.NewCallbackWithOutput<pp::VideoFrame_Private>( |
| &VEDemoInstance::GetFrameDone)); |
| } |
| |
| pp::Instance* VEDemoModule::CreateInstance(PP_Instance instance) { |
| return new VEDemoInstance(instance, this); |
| } |
| |
| } // anonymous namespace |
| |
| namespace pp { |
| // Factory function for your specialization of the Module object. |
| Module* CreateModule() { |
| return new VEDemoModule(); |
| } |
| } // namespace pp |