summaryrefslogtreecommitdiff
path: root/chromium/ppapi/examples/video_effects/video_effects.cc
blob: ab6dc354a02b2639c116154d13e71bc36492d78c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// 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 <stdint.h>
#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