Home | History | Annotate | Download | only in video_effects
      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