1 // Copyright 2014 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.
7 #include "ppapi/c/pp_errors.h"
8 #include "ppapi/c/ppb_opengles2.h"
9 #include "ppapi/cpp/completion_callback.h"
10 #include "ppapi/cpp/graphics_3d.h"
11 #include "ppapi/cpp/graphics_3d_client.h"
12 #include "ppapi/cpp/instance.h"
13 #include "ppapi/cpp/media_stream_video_track.h"
14 #include "ppapi/cpp/module.h"
15 #include "ppapi/cpp/rect.h"
16 #include "ppapi/cpp/var.h"
17 #include "ppapi/cpp/video_frame.h"
18 #include "ppapi/lib/gl/include/GLES2/gl2.h"
19 #include "ppapi/lib/gl/include/GLES2/gl2ext.h"
20 #include "ppapi/utility/completion_callback_factory.h"
22 // When compiling natively on Windows, PostMessage can be #define-d to
28 // Assert |context_| isn't holding any GL Errors. Done as a macro instead of a
29 // function to preserve line number information in the failure message.
30 #define AssertNoGLError() \
31 PP_DCHECK(!gles2_if_->GetError(context_->pp_resource()));
35 // This object is the global object representing this plugin library as long
37 class MediaStreamVideoModule : public pp::Module {
39 MediaStreamVideoModule() : pp::Module() {}
40 virtual ~MediaStreamVideoModule() {}
42 virtual pp::Instance* CreateInstance(PP_Instance instance);
45 class MediaStreamVideoDemoInstance : public pp::Instance,
46 public pp::Graphics3DClient {
48 MediaStreamVideoDemoInstance(PP_Instance instance, pp::Module* module);
49 virtual ~MediaStreamVideoDemoInstance();
51 // pp::Instance implementation (see PPP_Instance).
52 virtual void DidChangeView(const pp::Rect& position,
53 const pp::Rect& clip_ignored);
54 virtual void HandleMessage(const pp::Var& message_data);
56 // pp::Graphics3DClient implementation.
57 virtual void Graphics3DContextLost() {
68 // GL-related functions.
70 GLuint CreateTexture(int32_t width, int32_t height, int unit, bool rgba);
71 void CreateGLObjects();
72 void CreateShader(GLuint program, GLenum type, const char* source, int size);
73 void PaintFinished(int32_t result);
74 void CreateTextures();
75 void ConfigureTrack();
78 // MediaStreamVideoTrack callbacks.
79 void OnConfigure(int32_t result);
80 void OnGetFrame(int32_t result, pp::VideoFrame frame);
82 pp::Size position_size_;
93 pp::MediaStreamVideoTrack video_track_;
94 pp::CompletionCallbackFactory<MediaStreamVideoDemoInstance> callback_factory_;
95 std::vector<int32_t> attrib_list_;
97 // MediaStreamVideoTrack attributes:
99 PP_VideoFrame_Format attrib_format_;
100 int32_t attrib_width_;
101 int32_t attrib_height_;
104 const struct PPB_OpenGLES2* gles2_if_;
107 pp::Graphics3D* context_;
109 pp::Size frame_size_;
112 MediaStreamVideoDemoInstance::MediaStreamVideoDemoInstance(
113 PP_Instance instance, pp::Module* module)
114 : pp::Instance(instance),
115 pp::Graphics3DClient(this),
123 callback_factory_(this),
125 attrib_format_(PP_VIDEOFRAME_FORMAT_I420),
129 gles2_if_ = static_cast<const struct PPB_OpenGLES2*>(
130 module->GetBrowserInterface(PPB_OPENGLES2_INTERFACE));
131 PP_DCHECK(gles2_if_);
134 MediaStreamVideoDemoInstance::~MediaStreamVideoDemoInstance() {
138 void MediaStreamVideoDemoInstance::DidChangeView(
139 const pp::Rect& position, const pp::Rect& clip_ignored) {
140 if (position.width() == 0 || position.height() == 0)
142 if (position.size() == position_size_)
145 position_size_ = position.size();
147 // Initialize graphics.
152 void MediaStreamVideoDemoInstance::HandleMessage(const pp::Var& var_message) {
153 if (!var_message.is_dictionary())
156 pp::VarDictionary var_dictionary_message(var_message);
157 std::string command = var_dictionary_message.Get("command").AsString();
159 if (command == "init") {
160 pp::Var var_track = var_dictionary_message.Get("track");
161 if (!var_track.is_resource())
163 pp::Resource resource_track = var_track.AsResource();
164 video_track_ = pp::MediaStreamVideoTrack(resource_track);
166 } else if (command == "format") {
167 std::string str_format = var_dictionary_message.Get("format").AsString();
168 if (str_format == "YV12") {
169 attrib_format_ = PP_VIDEOFRAME_FORMAT_YV12;
170 } else if (str_format == "I420") {
171 attrib_format_ = PP_VIDEOFRAME_FORMAT_I420;
172 } else if (str_format == "BGRA") {
173 attrib_format_ = PP_VIDEOFRAME_FORMAT_BGRA;
175 attrib_format_ = PP_VIDEOFRAME_FORMAT_UNKNOWN;
178 } else if (command == "size") {
179 attrib_width_ = var_dictionary_message.Get("width").AsInt();
180 attrib_height_ = var_dictionary_message.Get("height").AsInt();
185 void MediaStreamVideoDemoInstance::InitGL() {
186 PP_DCHECK(position_size_.width() && position_size_.height());
187 is_painting_ = false;
190 int32_t attributes[] = {
191 PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 0,
192 PP_GRAPHICS3DATTRIB_BLUE_SIZE, 8,
193 PP_GRAPHICS3DATTRIB_GREEN_SIZE, 8,
194 PP_GRAPHICS3DATTRIB_RED_SIZE, 8,
195 PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 0,
196 PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 0,
197 PP_GRAPHICS3DATTRIB_SAMPLES, 0,
198 PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, 0,
199 PP_GRAPHICS3DATTRIB_WIDTH, position_size_.width(),
200 PP_GRAPHICS3DATTRIB_HEIGHT, position_size_.height(),
201 PP_GRAPHICS3DATTRIB_NONE,
203 context_ = new pp::Graphics3D(this, attributes);
204 PP_DCHECK(!context_->is_null());
206 // Set viewport window size and clear color bit.
207 gles2_if_->ClearColor(context_->pp_resource(), 1, 0, 0, 1);
208 gles2_if_->Clear(context_->pp_resource(), GL_COLOR_BUFFER_BIT);
209 gles2_if_->Viewport(context_->pp_resource(), 0, 0,
210 position_size_.width(), position_size_.height());
212 BindGraphics(*context_);
218 void MediaStreamVideoDemoInstance::DrawYUV() {
219 PP_Resource context = context_->pp_resource();
220 static const float kColorMatrix[9] = {
221 1.1643828125f, 1.1643828125f, 1.1643828125f,
222 0.0f, -0.39176171875f, 2.017234375f,
223 1.59602734375f, -0.81296875f, 0.0f
226 gles2_if_->UseProgram(context, program_yuv_);
227 gles2_if_->Uniform1i(context, gles2_if_->GetUniformLocation(
228 context, program_yuv_, "y_texture"), 0);
229 gles2_if_->Uniform1i(context, gles2_if_->GetUniformLocation(
230 context, program_yuv_, "u_texture"), 1);
231 gles2_if_->Uniform1i(context, gles2_if_->GetUniformLocation(
232 context, program_yuv_, "v_texture"), 2);
233 gles2_if_->UniformMatrix3fv(
235 gles2_if_->GetUniformLocation(context, program_yuv_, "color_matrix"),
236 1, GL_FALSE, kColorMatrix);
239 GLint pos_location = gles2_if_->GetAttribLocation(
240 context, program_yuv_, "a_position");
241 GLint tc_location = gles2_if_->GetAttribLocation(
242 context, program_yuv_, "a_texCoord");
244 gles2_if_->EnableVertexAttribArray(context, pos_location);
245 gles2_if_->VertexAttribPointer(context, pos_location, 2,
246 GL_FLOAT, GL_FALSE, 0, 0);
247 gles2_if_->EnableVertexAttribArray(context, tc_location);
248 gles2_if_->VertexAttribPointer(
249 context, tc_location, 2, GL_FLOAT, GL_FALSE, 0,
250 static_cast<float*>(0) + 16); // Skip position coordinates.
253 gles2_if_->DrawArrays(context, GL_TRIANGLE_STRIP, 0, 4);
257 void MediaStreamVideoDemoInstance::DrawRGB() {
258 PP_Resource context = context_->pp_resource();
259 gles2_if_->UseProgram(context, program_rgb_);
260 gles2_if_->Uniform1i(context,
261 gles2_if_->GetUniformLocation(context, program_rgb_, "rgb_texture"), 3);
264 GLint pos_location = gles2_if_->GetAttribLocation(
265 context, program_rgb_, "a_position");
266 GLint tc_location = gles2_if_->GetAttribLocation(
267 context, program_rgb_, "a_texCoord");
269 gles2_if_->EnableVertexAttribArray(context, pos_location);
270 gles2_if_->VertexAttribPointer(context, pos_location, 2,
271 GL_FLOAT, GL_FALSE, 0, 0);
272 gles2_if_->EnableVertexAttribArray(context, tc_location);
273 gles2_if_->VertexAttribPointer(
274 context, tc_location, 2, GL_FLOAT, GL_FALSE, 0,
275 static_cast<float*>(0) + 16); // Skip position coordinates.
278 gles2_if_->DrawArrays(context, GL_TRIANGLE_STRIP, 4, 4);
281 void MediaStreamVideoDemoInstance::Render() {
282 PP_DCHECK(!is_painting_);
284 needs_paint_ = false;
290 gles2_if_->Clear(context_->pp_resource(), GL_COLOR_BUFFER_BIT);
292 pp::CompletionCallback cb = callback_factory_.NewCallback(
293 &MediaStreamVideoDemoInstance::PaintFinished);
294 context_->SwapBuffers(cb);
297 void MediaStreamVideoDemoInstance::PaintFinished(int32_t result) {
298 is_painting_ = false;
303 GLuint MediaStreamVideoDemoInstance::CreateTexture(
304 int32_t width, int32_t height, int unit, bool rgba) {
306 gles2_if_->GenTextures(context_->pp_resource(), 1, &texture_id);
309 // Assign parameters.
310 gles2_if_->ActiveTexture(context_->pp_resource(), GL_TEXTURE0 + unit);
311 gles2_if_->BindTexture(context_->pp_resource(), GL_TEXTURE_2D, texture_id);
312 gles2_if_->TexParameteri(
313 context_->pp_resource(), GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
315 gles2_if_->TexParameteri(
316 context_->pp_resource(), GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
318 gles2_if_->TexParameterf(
319 context_->pp_resource(), GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
321 gles2_if_->TexParameterf(
322 context_->pp_resource(), GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
325 gles2_if_->TexImage2D(
326 context_->pp_resource(), GL_TEXTURE_2D, 0,
327 rgba ? GL_BGRA_EXT : GL_LUMINANCE,
329 rgba ? GL_BGRA_EXT : GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
334 void MediaStreamVideoDemoInstance::CreateGLObjects() {
335 // Code and constants for shader.
336 static const char kVertexShader[] =
337 "varying vec2 v_texCoord; \n"
338 "attribute vec4 a_position; \n"
339 "attribute vec2 a_texCoord; \n"
342 " v_texCoord = a_texCoord; \n"
343 " gl_Position = a_position; \n"
346 static const char kFragmentShaderYUV[] =
347 "precision mediump float; \n"
348 "varying vec2 v_texCoord; \n"
349 "uniform sampler2D y_texture; \n"
350 "uniform sampler2D u_texture; \n"
351 "uniform sampler2D v_texture; \n"
352 "uniform mat3 color_matrix; \n"
356 " yuv.x = texture2D(y_texture, v_texCoord).r; \n"
357 " yuv.y = texture2D(u_texture, v_texCoord).r; \n"
358 " yuv.z = texture2D(v_texture, v_texCoord).r; \n"
359 " vec3 rgb = color_matrix * (yuv - vec3(0.0625, 0.5, 0.5));\n"
360 " gl_FragColor = vec4(rgb, 1.0); \n"
363 static const char kFragmentShaderRGB[] =
364 "precision mediump float; \n"
365 "varying vec2 v_texCoord; \n"
366 "uniform sampler2D rgb_texture; \n"
369 " gl_FragColor = texture2D(rgb_texture, v_texCoord); \n"
372 PP_Resource context = context_->pp_resource();
374 // Create shader programs.
375 program_yuv_ = gles2_if_->CreateProgram(context);
376 CreateShader(program_yuv_, GL_VERTEX_SHADER,
377 kVertexShader, sizeof(kVertexShader));
378 CreateShader(program_yuv_, GL_FRAGMENT_SHADER,
379 kFragmentShaderYUV, sizeof(kFragmentShaderYUV));
380 gles2_if_->LinkProgram(context, program_yuv_);
383 program_rgb_ = gles2_if_->CreateProgram(context);
384 CreateShader(program_rgb_, GL_VERTEX_SHADER,
385 kVertexShader, sizeof(kVertexShader));
386 CreateShader(program_rgb_, GL_FRAGMENT_SHADER,
387 kFragmentShaderRGB, sizeof(kFragmentShaderRGB));
388 gles2_if_->LinkProgram(context, program_rgb_);
391 // Assign vertex positions and texture coordinates to buffers for use in
393 static const float kVertices[] = {
394 -1, 1, -1, -1, 0, 1, 0, -1, // Position coordinates.
395 0, 1, 0, -1, 1, 1, 1, -1, // Position coordinates.
396 0, 0, 0, 1, 1, 0, 1, 1, // Texture coordinates.
397 0, 0, 0, 1, 1, 0, 1, 1, // Texture coordinates.
400 gles2_if_->GenBuffers(context, 1, &buffer_);
401 gles2_if_->BindBuffer(context, GL_ARRAY_BUFFER, buffer_);
402 gles2_if_->BufferData(context, GL_ARRAY_BUFFER,
403 sizeof(kVertices), kVertices, GL_STATIC_DRAW);
407 void MediaStreamVideoDemoInstance::CreateShader(
408 GLuint program, GLenum type, const char* source, int size) {
409 PP_Resource context = context_->pp_resource();
410 GLuint shader = gles2_if_->CreateShader(context, type);
411 gles2_if_->ShaderSource(context, shader, 1, &source, &size);
412 gles2_if_->CompileShader(context, shader);
413 gles2_if_->AttachShader(context, program, shader);
414 gles2_if_->DeleteShader(context, shader);
417 void MediaStreamVideoDemoInstance::CreateTextures() {
418 int32_t width = frame_size_.width();
419 int32_t height = frame_size_.height();
420 if (width == 0 || height == 0)
423 gles2_if_->DeleteTextures(context_->pp_resource(), 1, &texture_y_);
425 gles2_if_->DeleteTextures(context_->pp_resource(), 1, &texture_u_);
427 gles2_if_->DeleteTextures(context_->pp_resource(), 1, &texture_v_);
429 gles2_if_->DeleteTextures(context_->pp_resource(), 1, &texture_rgb_);
430 texture_y_ = CreateTexture(width, height, 0, false);
432 texture_u_ = CreateTexture(width / 2, height / 2, 1, false);
433 texture_v_ = CreateTexture(width / 2, height / 2, 2, false);
434 texture_rgb_ = CreateTexture(width, height, 3, true);
437 void MediaStreamVideoDemoInstance::ConfigureTrack() {
438 const int32_t attrib_list[] = {
439 PP_MEDIASTREAMVIDEOTRACK_ATTRIB_FORMAT, attrib_format_,
440 PP_MEDIASTREAMVIDEOTRACK_ATTRIB_WIDTH, attrib_width_,
441 PP_MEDIASTREAMVIDEOTRACK_ATTRIB_HEIGHT, attrib_height_,
442 PP_MEDIASTREAMVIDEOTRACK_ATTRIB_NONE
444 video_track_.Configure(attrib_list, callback_factory_.NewCallback(
445 &MediaStreamVideoDemoInstance::OnConfigure));
448 void MediaStreamVideoDemoInstance::OnConfigure(int32_t result) {
449 video_track_.GetFrame(callback_factory_.NewCallbackWithOutput(
450 &MediaStreamVideoDemoInstance::OnGetFrame));
453 void MediaStreamVideoDemoInstance::OnGetFrame(
454 int32_t result, pp::VideoFrame frame) {
457 const char* data = static_cast<const char*>(frame.GetDataBuffer());
459 frame.GetSize(&size);
461 if (size != frame_size_) {
466 is_bgra_ = (frame.GetFormat() == PP_VIDEOFRAME_FORMAT_BGRA);
468 int32_t width = frame_size_.width();
469 int32_t height = frame_size_.height();
471 gles2_if_->ActiveTexture(context_->pp_resource(), GL_TEXTURE0);
472 gles2_if_->TexSubImage2D(
473 context_->pp_resource(), GL_TEXTURE_2D, 0, 0, 0, width, height,
474 GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
476 data += width * height;
480 gles2_if_->ActiveTexture(context_->pp_resource(), GL_TEXTURE1);
481 gles2_if_->TexSubImage2D(
482 context_->pp_resource(), GL_TEXTURE_2D, 0, 0, 0, width, height,
483 GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
485 data += width * height;
486 gles2_if_->ActiveTexture(context_->pp_resource(), GL_TEXTURE2);
487 gles2_if_->TexSubImage2D(
488 context_->pp_resource(), GL_TEXTURE_2D, 0, 0, 0, width, height,
489 GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
491 gles2_if_->ActiveTexture(context_->pp_resource(), GL_TEXTURE3);
492 gles2_if_->TexSubImage2D(
493 context_->pp_resource(), GL_TEXTURE_2D, 0, 0, 0, width, height,
494 GL_BGRA_EXT, GL_UNSIGNED_BYTE, data);
502 video_track_.RecycleFrame(frame);
505 need_config_ = false;
507 video_track_.GetFrame(callback_factory_.NewCallbackWithOutput(
508 &MediaStreamVideoDemoInstance::OnGetFrame));
512 pp::Instance* MediaStreamVideoModule::CreateInstance(PP_Instance instance) {
513 return new MediaStreamVideoDemoInstance(instance, this);
516 } // anonymous namespace
519 // Factory function for your specialization of the Module object.
520 Module* CreateModule() {
521 return new MediaStreamVideoModule();