// 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