15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include <GLES2/gl2.h>
6c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include <GLES2/gl2ext.h>
7c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include <string.h>
8c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include <vector>
10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ppapi/c/pp_errors.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ppapi/c/ppb_opengles2.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ppapi/cpp/completion_callback.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ppapi/cpp/graphics_3d.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ppapi/cpp/graphics_3d_client.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ppapi/cpp/instance.h"
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ppapi/cpp/media_stream_video_track.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ppapi/cpp/module.h"
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ppapi/cpp/rect.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ppapi/cpp/var.h"
215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ppapi/cpp/var_dictionary.h"
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ppapi/cpp/video_frame.h"
23c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "ppapi/lib/gl/gles2/gl2ext_ppapi.h"
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ppapi/utility/completion_callback_factory.h"
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// When compiling natively on Windows, PostMessage can be #define-d to
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// something else.
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#ifdef PostMessage
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#undef PostMessage
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Assert |context_| isn't holding any GL Errors.  Done as a macro instead of a
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// function to preserve line number information in the failure message.
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#define AssertNoGLError() \
35c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  PP_DCHECK(!glGetError());
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// This object is the global object representing this plugin library as long
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// as it is loaded.
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class MediaStreamVideoModule : public pp::Module {
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MediaStreamVideoModule() : pp::Module() {}
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ~MediaStreamVideoModule() {}
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual pp::Instance* CreateInstance(PP_Instance instance);
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class MediaStreamVideoDemoInstance : public pp::Instance,
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        public pp::Graphics3DClient {
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MediaStreamVideoDemoInstance(PP_Instance instance, pp::Module* module);
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ~MediaStreamVideoDemoInstance();
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // pp::Instance implementation (see PPP_Instance).
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void DidChangeView(const pp::Rect& position,
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             const pp::Rect& clip_ignored);
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void HandleMessage(const pp::Var& message_data);
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // pp::Graphics3DClient implementation.
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void Graphics3DContextLost() {
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    InitGL();
63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    CreateTextures();
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Render();
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void DrawYUV();
69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void DrawRGB();
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void Render();
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // GL-related functions.
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void InitGL();
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  GLuint CreateTexture(int32_t width, int32_t height, int unit, bool rgba);
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void CreateGLObjects();
76c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  void CreateShader(GLuint program, GLenum type, const char* source);
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void PaintFinished(int32_t result);
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void CreateTextures();
79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void ConfigureTrack();
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // MediaStreamVideoTrack callbacks.
83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void OnConfigure(int32_t result);
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void OnGetFrame(int32_t result, pp::VideoFrame frame);
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  pp::Size position_size_;
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool is_painting_;
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool needs_paint_;
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool is_bgra_;
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  GLuint program_yuv_;
91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  GLuint program_rgb_;
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  GLuint buffer_;
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GLuint texture_y_;
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GLuint texture_u_;
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GLuint texture_v_;
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  GLuint texture_rgb_;
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  pp::MediaStreamVideoTrack video_track_;
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  pp::CompletionCallbackFactory<MediaStreamVideoDemoInstance> callback_factory_;
99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::vector<int32_t> attrib_list_;
100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // MediaStreamVideoTrack attributes:
102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool need_config_;
103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  PP_VideoFrame_Format attrib_format_;
104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int32_t attrib_width_;
105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int32_t attrib_height_;
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Owned data.
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  pp::Graphics3D* context_;
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  pp::Size frame_size_;
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)MediaStreamVideoDemoInstance::MediaStreamVideoDemoInstance(
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PP_Instance instance, pp::Module* module)
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : pp::Instance(instance),
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      pp::Graphics3DClient(this),
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      is_painting_(false),
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      needs_paint_(false),
119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      is_bgra_(false),
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      texture_y_(0),
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      texture_u_(0),
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      texture_v_(0),
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      texture_rgb_(0),
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      callback_factory_(this),
125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      need_config_(false),
126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      attrib_format_(PP_VIDEOFRAME_FORMAT_I420),
127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      attrib_width_(0),
128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      attrib_height_(0),
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      context_(NULL) {
130c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!glInitializePPAPI(pp::Module::Get()->get_browser_interface())) {
131c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    LogToConsole(PP_LOGLEVEL_ERROR, pp::Var("Unable to initialize GL PPAPI!"));
132c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    assert(false);
133c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)MediaStreamVideoDemoInstance::~MediaStreamVideoDemoInstance() {
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  delete context_;
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MediaStreamVideoDemoInstance::DidChangeView(
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const pp::Rect& position, const pp::Rect& clip_ignored) {
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (position.width() == 0 || position.height() == 0)
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (position.size() == position_size_)
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  position_size_ = position.size();
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Initialize graphics.
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  InitGL();
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Render();
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MediaStreamVideoDemoInstance::HandleMessage(const pp::Var& var_message) {
155c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!var_message.is_dictionary()) {
156c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    LogToConsole(PP_LOGLEVEL_ERROR, pp::Var("Invalid message!"));
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
158c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  pp::VarDictionary var_dictionary_message(var_message);
161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::string command = var_dictionary_message.Get("command").AsString();
162a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
163a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (command == "init") {
164a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    pp::Var var_track = var_dictionary_message.Get("track");
165a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (!var_track.is_resource())
166a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return;
167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    pp::Resource resource_track = var_track.AsResource();
168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    video_track_ = pp::MediaStreamVideoTrack(resource_track);
169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ConfigureTrack();
170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else if (command == "format") {
171c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    std::string str_format = var_dictionary_message.Get("format").AsString();
172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (str_format == "YV12") {
173a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      attrib_format_ = PP_VIDEOFRAME_FORMAT_YV12;
174a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    } else if (str_format == "I420") {
175a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      attrib_format_ = PP_VIDEOFRAME_FORMAT_I420;
176a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    } else if (str_format == "BGRA") {
177a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      attrib_format_ = PP_VIDEOFRAME_FORMAT_BGRA;
178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    } else {
179a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      attrib_format_ = PP_VIDEOFRAME_FORMAT_UNKNOWN;
180a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
181a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    need_config_ = true;
182a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else if (command == "size") {
183a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    attrib_width_ = var_dictionary_message.Get("width").AsInt();
184a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    attrib_height_ = var_dictionary_message.Get("height").AsInt();
185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    need_config_ = true;
186c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  } else {
187c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    LogToConsole(PP_LOGLEVEL_ERROR, pp::Var("Invalid command!"));
188a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MediaStreamVideoDemoInstance::InitGL() {
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PP_DCHECK(position_size_.width() && position_size_.height());
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  is_painting_ = false;
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  delete context_;
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int32_t attributes[] = {
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 0,
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PP_GRAPHICS3DATTRIB_BLUE_SIZE, 8,
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PP_GRAPHICS3DATTRIB_GREEN_SIZE, 8,
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PP_GRAPHICS3DATTRIB_RED_SIZE, 8,
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 0,
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 0,
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PP_GRAPHICS3DATTRIB_SAMPLES, 0,
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, 0,
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PP_GRAPHICS3DATTRIB_WIDTH, position_size_.width(),
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PP_GRAPHICS3DATTRIB_HEIGHT, position_size_.height(),
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PP_GRAPHICS3DATTRIB_NONE,
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  };
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  context_ = new pp::Graphics3D(this, attributes);
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PP_DCHECK(!context_->is_null());
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
212c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glSetCurrentContextPPAPI(context_->pp_resource());
213c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Set viewport window size and clear color bit.
215c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glClearColor(1, 0, 0, 1);
216c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glClear(GL_COLOR_BUFFER_BIT);
217c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glViewport(0, 0, position_size_.width(), position_size_.height());
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  BindGraphics(*context_);
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AssertNoGLError();
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateGLObjects();
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void MediaStreamVideoDemoInstance::DrawYUV() {
226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  static const float kColorMatrix[9] = {
227a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    1.1643828125f, 1.1643828125f, 1.1643828125f,
228a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    0.0f, -0.39176171875f, 2.017234375f,
229a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    1.59602734375f, -0.81296875f, 0.0f
230a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  };
231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
232c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glUseProgram(program_yuv_);
233c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glUniform1i(glGetUniformLocation(program_yuv_, "y_texture"), 0);
234c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glUniform1i(glGetUniformLocation(program_yuv_, "u_texture"), 1);
235c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glUniform1i(glGetUniformLocation(program_yuv_, "v_texture"), 2);
236c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glUniformMatrix3fv(glGetUniformLocation(program_yuv_, "color_matrix"),
237a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      1, GL_FALSE, kColorMatrix);
238a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  AssertNoGLError();
239a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
240c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  GLint pos_location = glGetAttribLocation(program_yuv_, "a_position");
241c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  GLint tc_location = glGetAttribLocation(program_yuv_, "a_texCoord");
242a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  AssertNoGLError();
243c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glEnableVertexAttribArray(pos_location);
244c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, 0);
245c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glEnableVertexAttribArray(tc_location);
246c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0,
247a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      static_cast<float*>(0) + 16);  // Skip position coordinates.
248a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  AssertNoGLError();
249a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
250c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
251a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  AssertNoGLError();
252a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
253a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void MediaStreamVideoDemoInstance::DrawRGB() {
255c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glUseProgram(program_rgb_);
256c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glUniform1i(glGetUniformLocation(program_rgb_, "rgb_texture"), 3);
257a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  AssertNoGLError();
258a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
259c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  GLint pos_location = glGetAttribLocation(program_rgb_, "a_position");
260c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  GLint tc_location = glGetAttribLocation(program_rgb_, "a_texCoord");
261a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  AssertNoGLError();
262c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glEnableVertexAttribArray(pos_location);
263c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, 0);
264c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glEnableVertexAttribArray(tc_location);
265c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0,
266a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      static_cast<float*>(0) + 16);  // Skip position coordinates.
267a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  AssertNoGLError();
268a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
269c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glDrawArrays(GL_TRIANGLE_STRIP, 4, 4);
270a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
271a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MediaStreamVideoDemoInstance::Render() {
2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PP_DCHECK(!is_painting_);
2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  is_painting_ = true;
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  needs_paint_ = false;
276a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (texture_y_) {
278a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DrawRGB();
279a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DrawYUV();
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
281c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    glClear(GL_COLOR_BUFFER_BIT);
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  pp::CompletionCallback cb = callback_factory_.NewCallback(
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      &MediaStreamVideoDemoInstance::PaintFinished);
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  context_->SwapBuffers(cb);
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MediaStreamVideoDemoInstance::PaintFinished(int32_t result) {
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  is_painting_ = false;
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (needs_paint_)
2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Render();
2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)GLuint MediaStreamVideoDemoInstance::CreateTexture(
295a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    int32_t width, int32_t height, int unit, bool rgba) {
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GLuint texture_id;
297c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glGenTextures(1, &texture_id);
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AssertNoGLError();
299a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Assign parameters.
301c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glActiveTexture(GL_TEXTURE0 + unit);
302c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glBindTexture(GL_TEXTURE_2D, texture_id);
303c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
304c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
305c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
306c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Allocate texture.
308c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glTexImage2D(GL_TEXTURE_2D, 0,
309c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch               rgba ? GL_BGRA_EXT : GL_LUMINANCE,
310c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch               width, height, 0,
311c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch               rgba ? GL_BGRA_EXT : GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AssertNoGLError();
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return texture_id;
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MediaStreamVideoDemoInstance::CreateGLObjects() {
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Code and constants for shader.
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const char kVertexShader[] =
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "varying vec2 v_texCoord;            \n"
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "attribute vec4 a_position;          \n"
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "attribute vec2 a_texCoord;          \n"
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "void main()                         \n"
3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "{                                   \n"
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "    v_texCoord = a_texCoord;        \n"
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "    gl_Position = a_position;       \n"
3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "}";
3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
328a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  static const char kFragmentShaderYUV[] =
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "precision mediump float;                                   \n"
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "varying vec2 v_texCoord;                                   \n"
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "uniform sampler2D y_texture;                               \n"
3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "uniform sampler2D u_texture;                               \n"
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "uniform sampler2D v_texture;                               \n"
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "uniform mat3 color_matrix;                                 \n"
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "void main()                                                \n"
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "{                                                          \n"
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "  vec3 yuv;                                                \n"
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "  yuv.x = texture2D(y_texture, v_texCoord).r;              \n"
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "  yuv.y = texture2D(u_texture, v_texCoord).r;              \n"
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "  yuv.z = texture2D(v_texture, v_texCoord).r;              \n"
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "  vec3 rgb = color_matrix * (yuv - vec3(0.0625, 0.5, 0.5));\n"
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "  gl_FragColor = vec4(rgb, 1.0);                           \n"
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "}";
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
345a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  static const char kFragmentShaderRGB[] =
346a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "precision mediump float;                                   \n"
347a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "varying vec2 v_texCoord;                                   \n"
348a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "uniform sampler2D rgb_texture;                             \n"
349a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "void main()                                                \n"
350a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "{                                                          \n"
351a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "  gl_FragColor = texture2D(rgb_texture, v_texCoord);       \n"
352a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "}";
3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
354a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Create shader programs.
355c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  program_yuv_ = glCreateProgram();
356c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  CreateShader(program_yuv_, GL_VERTEX_SHADER, kVertexShader);
357c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  CreateShader(program_yuv_, GL_FRAGMENT_SHADER, kFragmentShaderYUV);
358c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glLinkProgram(program_yuv_);
359a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  AssertNoGLError();
360a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
361c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  program_rgb_ = glCreateProgram();
362c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  CreateShader(program_rgb_, GL_VERTEX_SHADER, kVertexShader);
363c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  CreateShader(program_rgb_, GL_FRAGMENT_SHADER, kFragmentShaderRGB);
364c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glLinkProgram(program_rgb_);
3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AssertNoGLError();
3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Assign vertex positions and texture coordinates to buffers for use in
3685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // shader program.
3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const float kVertices[] = {
370a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    -1, 1, -1, -1, 0, 1, 0, -1,  // Position coordinates.
371a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    0, 1, 0, -1, 1, 1, 1, -1,  // Position coordinates.
372a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    0, 0, 0, 1, 1, 0, 1, 1,  // Texture coordinates.
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    0, 0, 0, 1, 1, 0, 1, 1,  // Texture coordinates.
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  };
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
376c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glGenBuffers(1, &buffer_);
377c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glBindBuffer(GL_ARRAY_BUFFER, buffer_);
378c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glBufferData(GL_ARRAY_BUFFER, sizeof(kVertices), kVertices, GL_STATIC_DRAW);
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AssertNoGLError();
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MediaStreamVideoDemoInstance::CreateShader(
383c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    GLuint program, GLenum type, const char* source) {
384c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  GLuint shader = glCreateShader(type);
385c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  GLint length = static_cast<GLint>(strlen(source) + 1);
386c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glShaderSource(shader, 1, &source, &length);
387c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glCompileShader(shader);
388c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glAttachShader(program, shader);
389c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  glDeleteShader(shader);
3905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
392a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void MediaStreamVideoDemoInstance::CreateTextures() {
3935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int32_t width = frame_size_.width();
3945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int32_t height = frame_size_.height();
3955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (width == 0 || height == 0)
3965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (texture_y_)
398c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    glDeleteTextures(1, &texture_y_);
3995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (texture_u_)
400c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    glDeleteTextures(1, &texture_u_);
4015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (texture_v_)
402c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    glDeleteTextures(1, &texture_v_);
403a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (texture_rgb_)
404c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    glDeleteTextures(1, &texture_rgb_);
405a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  texture_y_ = CreateTexture(width, height, 0, false);
406a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
407a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  texture_u_ = CreateTexture(width / 2, height / 2, 1, false);
408a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  texture_v_ = CreateTexture(width / 2, height / 2, 2, false);
409a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  texture_rgb_ = CreateTexture(width, height, 3, true);
410a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
4115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
412a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void MediaStreamVideoDemoInstance::ConfigureTrack() {
413a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const int32_t attrib_list[] = {
414a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      PP_MEDIASTREAMVIDEOTRACK_ATTRIB_FORMAT, attrib_format_,
415a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      PP_MEDIASTREAMVIDEOTRACK_ATTRIB_WIDTH, attrib_width_,
416a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      PP_MEDIASTREAMVIDEOTRACK_ATTRIB_HEIGHT, attrib_height_,
417a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      PP_MEDIASTREAMVIDEOTRACK_ATTRIB_NONE
418a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    };
419a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  video_track_.Configure(attrib_list, callback_factory_.NewCallback(
420a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        &MediaStreamVideoDemoInstance::OnConfigure));
421a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
422a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
423a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void MediaStreamVideoDemoInstance::OnConfigure(int32_t result) {
424a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  video_track_.GetFrame(callback_factory_.NewCallbackWithOutput(
425a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      &MediaStreamVideoDemoInstance::OnGetFrame));
4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MediaStreamVideoDemoInstance::OnGetFrame(
4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int32_t result, pp::VideoFrame frame) {
4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (result != PP_OK)
4315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
4325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const char* data = static_cast<const char*>(frame.GetDataBuffer());
4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  pp::Size size;
4345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  frame.GetSize(&size);
4355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (size != frame_size_) {
4375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    frame_size_ = size;
438a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    CreateTextures();
4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
441a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  is_bgra_ = (frame.GetFormat() == PP_VIDEOFRAME_FORMAT_BGRA);
442a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int32_t width = frame_size_.width();
4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int32_t height = frame_size_.height();
445a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!is_bgra_) {
446c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    glActiveTexture(GL_TEXTURE0);
447c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height,
448c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                    GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
449a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
450a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    data += width * height;
451a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    width /= 2;
452a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    height /= 2;
453a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
454c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    glActiveTexture(GL_TEXTURE1);
455c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height,
456c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                    GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
457a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
458a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    data += width * height;
459c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    glActiveTexture(GL_TEXTURE2);
460c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height,
461c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                    GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
462a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else {
463c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    glActiveTexture(GL_TEXTURE3);
464c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height,
465c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                    GL_BGRA_EXT, GL_UNSIGNED_BYTE, data);
466a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
4675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (is_painting_)
4695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    needs_paint_ = true;
4705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  else
4715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Render();
4725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  video_track_.RecycleFrame(frame);
474a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (need_config_) {
475a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ConfigureTrack();
476a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    need_config_ = false;
477a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else {
478a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    video_track_.GetFrame(callback_factory_.NewCallbackWithOutput(
479a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        &MediaStreamVideoDemoInstance::OnGetFrame));
480a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
4815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)pp::Instance* MediaStreamVideoModule::CreateInstance(PP_Instance instance) {
4845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return new MediaStreamVideoDemoInstance(instance, this);
4855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // anonymous namespace
4885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace pp {
4905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Factory function for your specialization of the Module object.
4915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)Module* CreateModule() {
4925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return new MediaStreamVideoModule();
4935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace pp
495