| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "GLES2/gl2.h" | 5 #include <GLES2/gl2.h> |
| 6 #include <GLES2/gl2ext.h> |
| 7 #include <string.h> |
| 8 |
| 9 #include <vector> |
| 10 |
| 6 #include "ppapi/c/pp_errors.h" | 11 #include "ppapi/c/pp_errors.h" |
| 7 #include "ppapi/c/ppb_opengles2.h" | 12 #include "ppapi/c/ppb_opengles2.h" |
| 8 #include "ppapi/cpp/completion_callback.h" | 13 #include "ppapi/cpp/completion_callback.h" |
| 9 #include "ppapi/cpp/graphics_3d.h" | 14 #include "ppapi/cpp/graphics_3d.h" |
| 10 #include "ppapi/cpp/graphics_3d_client.h" | 15 #include "ppapi/cpp/graphics_3d_client.h" |
| 11 #include "ppapi/cpp/instance.h" | 16 #include "ppapi/cpp/instance.h" |
| 12 #include "ppapi/cpp/media_stream_video_track.h" | 17 #include "ppapi/cpp/media_stream_video_track.h" |
| 13 #include "ppapi/cpp/module.h" | 18 #include "ppapi/cpp/module.h" |
| 14 #include "ppapi/cpp/rect.h" | 19 #include "ppapi/cpp/rect.h" |
| 15 #include "ppapi/cpp/var.h" | 20 #include "ppapi/cpp/var.h" |
| 16 #include "ppapi/cpp/video_frame.h" | 21 #include "ppapi/cpp/video_frame.h" |
| 22 #include "ppapi/lib/gl/gles2/gl2ext_ppapi.h" |
| 17 #include "ppapi/utility/completion_callback_factory.h" | 23 #include "ppapi/utility/completion_callback_factory.h" |
| 18 | 24 |
| 19 // When compiling natively on Windows, PostMessage can be #define-d to | 25 // When compiling natively on Windows, PostMessage can be #define-d to |
| 20 // something else. | 26 // something else. |
| 21 #ifdef PostMessage | 27 #ifdef PostMessage |
| 22 #undef PostMessage | 28 #undef PostMessage |
| 23 #endif | 29 #endif |
| 24 | 30 |
| 25 // Assert |context_| isn't holding any GL Errors. Done as a macro instead of a | 31 // Assert |context_| isn't holding any GL Errors. Done as a macro instead of a |
| 26 // function to preserve line number information in the failure message. | 32 // function to preserve line number information in the failure message. |
| 27 #define AssertNoGLError() \ | 33 #define AssertNoGLError() \ |
| 28 PP_DCHECK(!gles2_if_->GetError(context_->pp_resource())); | 34 PP_DCHECK(!glGetError()); |
| 29 | 35 |
| 30 namespace { | 36 namespace { |
| 31 | 37 |
| 32 // This object is the global object representing this plugin library as long | 38 // This object is the global object representing this plugin library as long |
| 33 // as it is loaded. | 39 // as it is loaded. |
| 34 class MediaStreamVideoModule : public pp::Module { | 40 class MediaStreamVideoModule : public pp::Module { |
| 35 public: | 41 public: |
| 36 MediaStreamVideoModule() : pp::Module() {} | 42 MediaStreamVideoModule() : pp::Module() {} |
| 37 virtual ~MediaStreamVideoModule() {} | 43 virtual ~MediaStreamVideoModule() {} |
| 38 | 44 |
| 39 virtual pp::Instance* CreateInstance(PP_Instance instance); | 45 virtual pp::Instance* CreateInstance(PP_Instance instance); |
| 40 }; | 46 }; |
| 41 | 47 |
| 42 class MediaStreamVideoDemoInstance : public pp::Instance, | 48 class MediaStreamVideoDemoInstance : public pp::Instance, |
| 43 public pp::Graphics3DClient { | 49 public pp::Graphics3DClient { |
| 44 public: | 50 public: |
| 45 MediaStreamVideoDemoInstance(PP_Instance instance, pp::Module* module); | 51 MediaStreamVideoDemoInstance(PP_Instance instance, pp::Module* module); |
| 46 virtual ~MediaStreamVideoDemoInstance(); | 52 virtual ~MediaStreamVideoDemoInstance(); |
| 47 | 53 |
| 48 // pp::Instance implementation (see PPP_Instance). | 54 // pp::Instance implementation (see PPP_Instance). |
| 49 virtual void DidChangeView(const pp::Rect& position, | 55 virtual void DidChangeView(const pp::Rect& position, |
| 50 const pp::Rect& clip_ignored); | 56 const pp::Rect& clip_ignored); |
| 51 virtual void HandleMessage(const pp::Var& message_data); | 57 virtual void HandleMessage(const pp::Var& message_data); |
| 52 | 58 |
| 53 // pp::Graphics3DClient implementation. | 59 // pp::Graphics3DClient implementation. |
| 54 virtual void Graphics3DContextLost() { | 60 virtual void Graphics3DContextLost() { |
| 55 InitGL(); | 61 InitGL(); |
| 56 CreateYUVTextures(); | 62 CreateTextures(); |
| 57 Render(); | 63 Render(); |
| 58 } | 64 } |
| 59 | 65 |
| 60 private: | 66 private: |
| 67 void DrawYUV(); |
| 68 void DrawRGB(); |
| 61 void Render(); | 69 void Render(); |
| 62 | 70 |
| 63 // GL-related functions. | 71 // GL-related functions. |
| 64 void InitGL(); | 72 void InitGL(); |
| 65 GLuint CreateTexture(int32_t width, int32_t height, int unit); | 73 GLuint CreateTexture(int32_t width, int32_t height, int unit, bool rgba); |
| 66 void CreateGLObjects(); | 74 void CreateGLObjects(); |
| 67 void CreateShader(GLuint program, GLenum type, const char* source, int size); | 75 void CreateShader(GLuint program, GLenum type, const char* source); |
| 68 void PaintFinished(int32_t result); | 76 void PaintFinished(int32_t result); |
| 69 void CreateYUVTextures(); | 77 void CreateTextures(); |
| 78 void ConfigureTrack(); |
| 70 | 79 |
| 71 // Callback that is invoked when new frames are recevied. | 80 |
| 81 // MediaStreamVideoTrack callbacks. |
| 82 void OnConfigure(int32_t result); |
| 72 void OnGetFrame(int32_t result, pp::VideoFrame frame); | 83 void OnGetFrame(int32_t result, pp::VideoFrame frame); |
| 73 | 84 |
| 74 pp::Size position_size_; | 85 pp::Size position_size_; |
| 75 bool is_painting_; | 86 bool is_painting_; |
| 76 bool needs_paint_; | 87 bool needs_paint_; |
| 88 bool is_bgra_; |
| 89 GLuint program_yuv_; |
| 90 GLuint program_rgb_; |
| 91 GLuint buffer_; |
| 77 GLuint texture_y_; | 92 GLuint texture_y_; |
| 78 GLuint texture_u_; | 93 GLuint texture_u_; |
| 79 GLuint texture_v_; | 94 GLuint texture_v_; |
| 95 GLuint texture_rgb_; |
| 80 pp::MediaStreamVideoTrack video_track_; | 96 pp::MediaStreamVideoTrack video_track_; |
| 81 pp::CompletionCallbackFactory<MediaStreamVideoDemoInstance> callback_factory_; | 97 pp::CompletionCallbackFactory<MediaStreamVideoDemoInstance> callback_factory_; |
| 98 std::vector<int32_t> attrib_list_; |
| 82 | 99 |
| 83 // Unowned pointers. | 100 // MediaStreamVideoTrack attributes: |
| 84 const struct PPB_OpenGLES2* gles2_if_; | 101 bool need_config_; |
| 102 PP_VideoFrame_Format attrib_format_; |
| 103 int32_t attrib_width_; |
| 104 int32_t attrib_height_; |
| 85 | 105 |
| 86 // Owned data. | 106 // Owned data. |
| 87 pp::Graphics3D* context_; | 107 pp::Graphics3D* context_; |
| 88 | 108 |
| 89 pp::Size frame_size_; | 109 pp::Size frame_size_; |
| 90 }; | 110 }; |
| 91 | 111 |
| 92 MediaStreamVideoDemoInstance::MediaStreamVideoDemoInstance( | 112 MediaStreamVideoDemoInstance::MediaStreamVideoDemoInstance( |
| 93 PP_Instance instance, pp::Module* module) | 113 PP_Instance instance, pp::Module* module) |
| 94 : pp::Instance(instance), | 114 : pp::Instance(instance), |
| 95 pp::Graphics3DClient(this), | 115 pp::Graphics3DClient(this), |
| 96 is_painting_(false), | 116 is_painting_(false), |
| 97 needs_paint_(false), | 117 needs_paint_(false), |
| 118 is_bgra_(false), |
| 98 texture_y_(0), | 119 texture_y_(0), |
| 99 texture_u_(0), | 120 texture_u_(0), |
| 100 texture_v_(0), | 121 texture_v_(0), |
| 122 texture_rgb_(0), |
| 101 callback_factory_(this), | 123 callback_factory_(this), |
| 124 need_config_(false), |
| 125 attrib_format_(PP_VIDEOFRAME_FORMAT_I420), |
| 126 attrib_width_(0), |
| 127 attrib_height_(0), |
| 102 context_(NULL) { | 128 context_(NULL) { |
| 103 gles2_if_ = static_cast<const struct PPB_OpenGLES2*>( | 129 if (!glInitializePPAPI(pp::Module::Get()->get_browser_interface())) { |
| 104 module->GetBrowserInterface(PPB_OPENGLES2_INTERFACE)); | 130 LogToConsole(PP_LOGLEVEL_ERROR, pp::Var("Unable to initialize GL PPAPI!")); |
| 105 PP_DCHECK(gles2_if_); | 131 assert(false); |
| 132 } |
| 106 } | 133 } |
| 107 | 134 |
| 108 MediaStreamVideoDemoInstance::~MediaStreamVideoDemoInstance() { | 135 MediaStreamVideoDemoInstance::~MediaStreamVideoDemoInstance() { |
| 109 delete context_; | 136 delete context_; |
| 110 } | 137 } |
| 111 | 138 |
| 112 void MediaStreamVideoDemoInstance::DidChangeView( | 139 void MediaStreamVideoDemoInstance::DidChangeView( |
| 113 const pp::Rect& position, const pp::Rect& clip_ignored) { | 140 const pp::Rect& position, const pp::Rect& clip_ignored) { |
| 114 if (position.width() == 0 || position.height() == 0) | 141 if (position.width() == 0 || position.height() == 0) |
| 115 return; | 142 return; |
| 116 if (position.size() == position_size_) | 143 if (position.size() == position_size_) |
| 117 return; | 144 return; |
| 118 | 145 |
| 119 position_size_ = position.size(); | 146 position_size_ = position.size(); |
| 120 | 147 |
| 121 // Initialize graphics. | 148 // Initialize graphics. |
| 122 InitGL(); | 149 InitGL(); |
| 123 Render(); | 150 Render(); |
| 124 } | 151 } |
| 125 | 152 |
| 126 void MediaStreamVideoDemoInstance::HandleMessage(const pp::Var& var_message) { | 153 void MediaStreamVideoDemoInstance::HandleMessage(const pp::Var& var_message) { |
| 127 if (!var_message.is_dictionary()) | 154 if (!var_message.is_dictionary()) { |
| 155 LogToConsole(PP_LOGLEVEL_ERROR, pp::Var("Invalid message!")); |
| 128 return; | 156 return; |
| 157 } |
| 158 |
| 129 pp::VarDictionary var_dictionary_message(var_message); | 159 pp::VarDictionary var_dictionary_message(var_message); |
| 130 pp::Var var_track = var_dictionary_message.Get("track"); | 160 std::string command = var_dictionary_message.Get("command").AsString(); |
| 131 if (!var_track.is_resource()) | |
| 132 return; | |
| 133 | 161 |
| 134 pp::Resource resource_track = var_track.AsResource(); | 162 if (command == "init") { |
| 135 | 163 pp::Var var_track = var_dictionary_message.Get("track"); |
| 136 video_track_ = pp::MediaStreamVideoTrack(resource_track); | 164 if (!var_track.is_resource()) |
| 137 | 165 return; |
| 138 video_track_.GetFrame(callback_factory_.NewCallbackWithOutput( | 166 pp::Resource resource_track = var_track.AsResource(); |
| 139 &MediaStreamVideoDemoInstance::OnGetFrame)); | 167 video_track_ = pp::MediaStreamVideoTrack(resource_track); |
| 168 ConfigureTrack(); |
| 169 } else if (command == "format") { |
| 170 std::string str_format = var_dictionary_message.Get("format").AsString(); |
| 171 if (str_format == "YV12") { |
| 172 attrib_format_ = PP_VIDEOFRAME_FORMAT_YV12; |
| 173 } else if (str_format == "I420") { |
| 174 attrib_format_ = PP_VIDEOFRAME_FORMAT_I420; |
| 175 } else if (str_format == "BGRA") { |
| 176 attrib_format_ = PP_VIDEOFRAME_FORMAT_BGRA; |
| 177 } else { |
| 178 attrib_format_ = PP_VIDEOFRAME_FORMAT_UNKNOWN; |
| 179 } |
| 180 need_config_ = true; |
| 181 } else if (command == "size") { |
| 182 attrib_width_ = var_dictionary_message.Get("width").AsInt(); |
| 183 attrib_height_ = var_dictionary_message.Get("height").AsInt(); |
| 184 need_config_ = true; |
| 185 } else { |
| 186 LogToConsole(PP_LOGLEVEL_ERROR, pp::Var("Invalid command!")); |
| 187 } |
| 140 } | 188 } |
| 141 | 189 |
| 142 void MediaStreamVideoDemoInstance::InitGL() { | 190 void MediaStreamVideoDemoInstance::InitGL() { |
| 143 PP_DCHECK(position_size_.width() && position_size_.height()); | 191 PP_DCHECK(position_size_.width() && position_size_.height()); |
| 144 is_painting_ = false; | 192 is_painting_ = false; |
| 145 | 193 |
| 146 delete context_; | 194 delete context_; |
| 147 int32_t attributes[] = { | 195 int32_t attributes[] = { |
| 148 PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 0, | 196 PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 0, |
| 149 PP_GRAPHICS3DATTRIB_BLUE_SIZE, 8, | 197 PP_GRAPHICS3DATTRIB_BLUE_SIZE, 8, |
| 150 PP_GRAPHICS3DATTRIB_GREEN_SIZE, 8, | 198 PP_GRAPHICS3DATTRIB_GREEN_SIZE, 8, |
| 151 PP_GRAPHICS3DATTRIB_RED_SIZE, 8, | 199 PP_GRAPHICS3DATTRIB_RED_SIZE, 8, |
| 152 PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 0, | 200 PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 0, |
| 153 PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 0, | 201 PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 0, |
| 154 PP_GRAPHICS3DATTRIB_SAMPLES, 0, | 202 PP_GRAPHICS3DATTRIB_SAMPLES, 0, |
| 155 PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, 0, | 203 PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, 0, |
| 156 PP_GRAPHICS3DATTRIB_WIDTH, position_size_.width(), | 204 PP_GRAPHICS3DATTRIB_WIDTH, position_size_.width(), |
| 157 PP_GRAPHICS3DATTRIB_HEIGHT, position_size_.height(), | 205 PP_GRAPHICS3DATTRIB_HEIGHT, position_size_.height(), |
| 158 PP_GRAPHICS3DATTRIB_NONE, | 206 PP_GRAPHICS3DATTRIB_NONE, |
| 159 }; | 207 }; |
| 160 context_ = new pp::Graphics3D(this, attributes); | 208 context_ = new pp::Graphics3D(this, attributes); |
| 161 PP_DCHECK(!context_->is_null()); | 209 PP_DCHECK(!context_->is_null()); |
| 162 | 210 |
| 211 glSetCurrentContextPPAPI(context_->pp_resource()); |
| 212 |
| 163 // Set viewport window size and clear color bit. | 213 // Set viewport window size and clear color bit. |
| 164 gles2_if_->ClearColor(context_->pp_resource(), 1, 0, 0, 1); | 214 glClearColor(1, 0, 0, 1); |
| 165 gles2_if_->Clear(context_->pp_resource(), GL_COLOR_BUFFER_BIT); | 215 glClear(GL_COLOR_BUFFER_BIT); |
| 166 gles2_if_->Viewport(context_->pp_resource(), 0, 0, | 216 glViewport(0, 0, position_size_.width(), position_size_.height()); |
| 167 position_size_.width(), position_size_.height()); | |
| 168 | 217 |
| 169 BindGraphics(*context_); | 218 BindGraphics(*context_); |
| 170 AssertNoGLError(); | 219 AssertNoGLError(); |
| 171 | 220 |
| 172 CreateGLObjects(); | 221 CreateGLObjects(); |
| 173 } | 222 } |
| 174 | 223 |
| 224 void MediaStreamVideoDemoInstance::DrawYUV() { |
| 225 static const float kColorMatrix[9] = { |
| 226 1.1643828125f, 1.1643828125f, 1.1643828125f, |
| 227 0.0f, -0.39176171875f, 2.017234375f, |
| 228 1.59602734375f, -0.81296875f, 0.0f |
| 229 }; |
| 230 |
| 231 glUseProgram(program_yuv_); |
| 232 glUniform1i(glGetUniformLocation(program_yuv_, "y_texture"), 0); |
| 233 glUniform1i(glGetUniformLocation(program_yuv_, "u_texture"), 1); |
| 234 glUniform1i(glGetUniformLocation(program_yuv_, "v_texture"), 2); |
| 235 glUniformMatrix3fv(glGetUniformLocation(program_yuv_, "color_matrix"), |
| 236 1, GL_FALSE, kColorMatrix); |
| 237 AssertNoGLError(); |
| 238 |
| 239 GLint pos_location = glGetAttribLocation(program_yuv_, "a_position"); |
| 240 GLint tc_location = glGetAttribLocation(program_yuv_, "a_texCoord"); |
| 241 AssertNoGLError(); |
| 242 glEnableVertexAttribArray(pos_location); |
| 243 glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, 0); |
| 244 glEnableVertexAttribArray(tc_location); |
| 245 glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, |
| 246 static_cast<float*>(0) + 16); // Skip position coordinates. |
| 247 AssertNoGLError(); |
| 248 |
| 249 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| 250 AssertNoGLError(); |
| 251 } |
| 252 |
| 253 void MediaStreamVideoDemoInstance::DrawRGB() { |
| 254 glUseProgram(program_rgb_); |
| 255 glUniform1i(glGetUniformLocation(program_rgb_, "rgb_texture"), 3); |
| 256 AssertNoGLError(); |
| 257 |
| 258 GLint pos_location = glGetAttribLocation(program_rgb_, "a_position"); |
| 259 GLint tc_location = glGetAttribLocation(program_rgb_, "a_texCoord"); |
| 260 AssertNoGLError(); |
| 261 glEnableVertexAttribArray(pos_location); |
| 262 glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, 0); |
| 263 glEnableVertexAttribArray(tc_location); |
| 264 glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, |
| 265 static_cast<float*>(0) + 16); // Skip position coordinates. |
| 266 AssertNoGLError(); |
| 267 |
| 268 glDrawArrays(GL_TRIANGLE_STRIP, 4, 4); |
| 269 } |
| 270 |
| 175 void MediaStreamVideoDemoInstance::Render() { | 271 void MediaStreamVideoDemoInstance::Render() { |
| 176 PP_DCHECK(!is_painting_); | 272 PP_DCHECK(!is_painting_); |
| 177 is_painting_ = true; | 273 is_painting_ = true; |
| 178 needs_paint_ = false; | 274 needs_paint_ = false; |
| 275 |
| 179 if (texture_y_) { | 276 if (texture_y_) { |
| 180 gles2_if_->DrawArrays(context_->pp_resource(), GL_TRIANGLE_STRIP, 0, 4); | 277 DrawRGB(); |
| 278 DrawYUV(); |
| 181 } else { | 279 } else { |
| 182 gles2_if_->Clear(context_->pp_resource(), GL_COLOR_BUFFER_BIT); | 280 glClear(GL_COLOR_BUFFER_BIT); |
| 183 } | 281 } |
| 184 pp::CompletionCallback cb = callback_factory_.NewCallback( | 282 pp::CompletionCallback cb = callback_factory_.NewCallback( |
| 185 &MediaStreamVideoDemoInstance::PaintFinished); | 283 &MediaStreamVideoDemoInstance::PaintFinished); |
| 186 context_->SwapBuffers(cb); | 284 context_->SwapBuffers(cb); |
| 187 } | 285 } |
| 188 | 286 |
| 189 void MediaStreamVideoDemoInstance::PaintFinished(int32_t result) { | 287 void MediaStreamVideoDemoInstance::PaintFinished(int32_t result) { |
| 190 is_painting_ = false; | 288 is_painting_ = false; |
| 191 if (needs_paint_) | 289 if (needs_paint_) |
| 192 Render(); | 290 Render(); |
| 193 } | 291 } |
| 194 | 292 |
| 195 GLuint MediaStreamVideoDemoInstance::CreateTexture( | 293 GLuint MediaStreamVideoDemoInstance::CreateTexture( |
| 196 int32_t width, int32_t height, int unit) { | 294 int32_t width, int32_t height, int unit, bool rgba) { |
| 197 GLuint texture_id; | 295 GLuint texture_id; |
| 198 gles2_if_->GenTextures(context_->pp_resource(), 1, &texture_id); | 296 glGenTextures(1, &texture_id); |
| 199 AssertNoGLError(); | 297 AssertNoGLError(); |
| 298 |
| 200 // Assign parameters. | 299 // Assign parameters. |
| 201 gles2_if_->ActiveTexture(context_->pp_resource(), GL_TEXTURE0 + unit); | 300 glActiveTexture(GL_TEXTURE0 + unit); |
| 202 gles2_if_->BindTexture(context_->pp_resource(), GL_TEXTURE_2D, texture_id); | 301 glBindTexture(GL_TEXTURE_2D, texture_id); |
| 203 gles2_if_->TexParameteri( | 302 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| 204 context_->pp_resource(), GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, | 303 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| 205 GL_NEAREST); | 304 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| 206 gles2_if_->TexParameteri( | 305 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| 207 context_->pp_resource(), GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, | |
| 208 GL_NEAREST); | |
| 209 gles2_if_->TexParameterf( | |
| 210 context_->pp_resource(), GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, | |
| 211 GL_CLAMP_TO_EDGE); | |
| 212 gles2_if_->TexParameterf( | |
| 213 context_->pp_resource(), GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, | |
| 214 GL_CLAMP_TO_EDGE); | |
| 215 | |
| 216 // Allocate texture. | 306 // Allocate texture. |
| 217 gles2_if_->TexImage2D( | 307 glTexImage2D(GL_TEXTURE_2D, 0, |
| 218 context_->pp_resource(), GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, | 308 rgba ? GL_BGRA_EXT : GL_LUMINANCE, |
| 219 GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL); | 309 width, height, 0, |
| 310 rgba ? GL_BGRA_EXT : GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL); |
| 220 AssertNoGLError(); | 311 AssertNoGLError(); |
| 221 return texture_id; | 312 return texture_id; |
| 222 } | 313 } |
| 223 | 314 |
| 224 void MediaStreamVideoDemoInstance::CreateGLObjects() { | 315 void MediaStreamVideoDemoInstance::CreateGLObjects() { |
| 225 // Code and constants for shader. | 316 // Code and constants for shader. |
| 226 static const char kVertexShader[] = | 317 static const char kVertexShader[] = |
| 227 "varying vec2 v_texCoord; \n" | 318 "varying vec2 v_texCoord; \n" |
| 228 "attribute vec4 a_position; \n" | 319 "attribute vec4 a_position; \n" |
| 229 "attribute vec2 a_texCoord; \n" | 320 "attribute vec2 a_texCoord; \n" |
| 230 "void main() \n" | 321 "void main() \n" |
| 231 "{ \n" | 322 "{ \n" |
| 232 " v_texCoord = a_texCoord; \n" | 323 " v_texCoord = a_texCoord; \n" |
| 233 " gl_Position = a_position; \n" | 324 " gl_Position = a_position; \n" |
| 234 "}"; | 325 "}"; |
| 235 | 326 |
| 236 static const char kFragmentShader[] = | 327 static const char kFragmentShaderYUV[] = |
| 237 "precision mediump float; \n" | 328 "precision mediump float; \n" |
| 238 "varying vec2 v_texCoord; \n" | 329 "varying vec2 v_texCoord; \n" |
| 239 "uniform sampler2D y_texture; \n" | 330 "uniform sampler2D y_texture; \n" |
| 240 "uniform sampler2D u_texture; \n" | 331 "uniform sampler2D u_texture; \n" |
| 241 "uniform sampler2D v_texture; \n" | 332 "uniform sampler2D v_texture; \n" |
| 242 "uniform mat3 color_matrix; \n" | 333 "uniform mat3 color_matrix; \n" |
| 243 "void main() \n" | 334 "void main() \n" |
| 244 "{ \n" | 335 "{ \n" |
| 245 " vec3 yuv; \n" | 336 " vec3 yuv; \n" |
| 246 " yuv.x = texture2D(y_texture, v_texCoord).r; \n" | 337 " yuv.x = texture2D(y_texture, v_texCoord).r; \n" |
| 247 " yuv.y = texture2D(u_texture, v_texCoord).r; \n" | 338 " yuv.y = texture2D(u_texture, v_texCoord).r; \n" |
| 248 " yuv.z = texture2D(v_texture, v_texCoord).r; \n" | 339 " yuv.z = texture2D(v_texture, v_texCoord).r; \n" |
| 249 " vec3 rgb = color_matrix * (yuv - vec3(0.0625, 0.5, 0.5));\n" | 340 " vec3 rgb = color_matrix * (yuv - vec3(0.0625, 0.5, 0.5));\n" |
| 250 " gl_FragColor = vec4(rgb, 1.0); \n" | 341 " gl_FragColor = vec4(rgb, 1.0); \n" |
| 251 "}"; | 342 "}"; |
| 252 | 343 |
| 253 static const float kColorMatrix[9] = { | 344 static const char kFragmentShaderRGB[] = |
| 254 1.1643828125f, 1.1643828125f, 1.1643828125f, | 345 "precision mediump float; \n" |
| 255 0.0f, -0.39176171875f, 2.017234375f, | 346 "varying vec2 v_texCoord; \n" |
| 256 1.59602734375f, -0.81296875f, 0.0f | 347 "uniform sampler2D rgb_texture; \n" |
| 257 }; | 348 "void main() \n" |
| 349 "{ \n" |
| 350 " gl_FragColor = texture2D(rgb_texture, v_texCoord); \n" |
| 351 "}"; |
| 258 | 352 |
| 259 PP_Resource context = context_->pp_resource(); | 353 // Create shader programs. |
| 354 program_yuv_ = glCreateProgram(); |
| 355 CreateShader(program_yuv_, GL_VERTEX_SHADER, kVertexShader); |
| 356 CreateShader(program_yuv_, GL_FRAGMENT_SHADER, kFragmentShaderYUV); |
| 357 glLinkProgram(program_yuv_); |
| 358 AssertNoGLError(); |
| 260 | 359 |
| 261 // Create shader program. | 360 program_rgb_ = glCreateProgram(); |
| 262 GLuint program = gles2_if_->CreateProgram(context); | 361 CreateShader(program_rgb_, GL_VERTEX_SHADER, kVertexShader); |
| 263 CreateShader(program, GL_VERTEX_SHADER, kVertexShader, sizeof(kVertexShader)); | 362 CreateShader(program_rgb_, GL_FRAGMENT_SHADER, kFragmentShaderRGB); |
| 264 CreateShader( | 363 glLinkProgram(program_rgb_); |
| 265 program, GL_FRAGMENT_SHADER, kFragmentShader, sizeof(kFragmentShader)); | |
| 266 gles2_if_->LinkProgram(context, program); | |
| 267 gles2_if_->UseProgram(context, program); | |
| 268 gles2_if_->DeleteProgram(context, program); | |
| 269 gles2_if_->Uniform1i( | |
| 270 context, gles2_if_->GetUniformLocation(context, program, "y_texture"), 0); | |
| 271 gles2_if_->Uniform1i( | |
| 272 context, gles2_if_->GetUniformLocation(context, program, "u_texture"), 1); | |
| 273 gles2_if_->Uniform1i( | |
| 274 context, gles2_if_->GetUniformLocation(context, program, "v_texture"), 2); | |
| 275 gles2_if_->UniformMatrix3fv( | |
| 276 context, | |
| 277 gles2_if_->GetUniformLocation(context, program, "color_matrix"), | |
| 278 1, GL_FALSE, kColorMatrix); | |
| 279 AssertNoGLError(); | 364 AssertNoGLError(); |
| 280 | 365 |
| 281 // Assign vertex positions and texture coordinates to buffers for use in | 366 // Assign vertex positions and texture coordinates to buffers for use in |
| 282 // shader program. | 367 // shader program. |
| 283 static const float kVertices[] = { | 368 static const float kVertices[] = { |
| 284 -1, 1, -1, -1, 1, 1, 1, -1, // Position coordinates. | 369 -1, 1, -1, -1, 0, 1, 0, -1, // Position coordinates. |
| 370 0, 1, 0, -1, 1, 1, 1, -1, // Position coordinates. |
| 371 0, 0, 0, 1, 1, 0, 1, 1, // Texture coordinates. |
| 285 0, 0, 0, 1, 1, 0, 1, 1, // Texture coordinates. | 372 0, 0, 0, 1, 1, 0, 1, 1, // Texture coordinates. |
| 286 }; | 373 }; |
| 287 | 374 |
| 288 GLuint buffer; | 375 glGenBuffers(1, &buffer_); |
| 289 gles2_if_->GenBuffers(context, 1, &buffer); | 376 glBindBuffer(GL_ARRAY_BUFFER, buffer_); |
| 290 gles2_if_->BindBuffer(context, GL_ARRAY_BUFFER, buffer); | 377 glBufferData(GL_ARRAY_BUFFER, sizeof(kVertices), kVertices, GL_STATIC_DRAW); |
| 291 gles2_if_->BufferData(context, GL_ARRAY_BUFFER, | |
| 292 sizeof(kVertices), kVertices, GL_STATIC_DRAW); | |
| 293 AssertNoGLError(); | |
| 294 GLint pos_location = gles2_if_->GetAttribLocation( | |
| 295 context, program, "a_position"); | |
| 296 GLint tc_location = gles2_if_->GetAttribLocation( | |
| 297 context, program, "a_texCoord"); | |
| 298 AssertNoGLError(); | |
| 299 gles2_if_->EnableVertexAttribArray(context, pos_location); | |
| 300 gles2_if_->VertexAttribPointer(context, pos_location, 2, | |
| 301 GL_FLOAT, GL_FALSE, 0, 0); | |
| 302 gles2_if_->EnableVertexAttribArray(context, tc_location); | |
| 303 gles2_if_->VertexAttribPointer( | |
| 304 context, tc_location, 2, GL_FLOAT, GL_FALSE, 0, | |
| 305 static_cast<float*>(0) + 8); // Skip position coordinates. | |
| 306 AssertNoGLError(); | 378 AssertNoGLError(); |
| 307 } | 379 } |
| 308 | 380 |
| 309 void MediaStreamVideoDemoInstance::CreateShader( | 381 void MediaStreamVideoDemoInstance::CreateShader( |
| 310 GLuint program, GLenum type, const char* source, int size) { | 382 GLuint program, GLenum type, const char* source) { |
| 311 PP_Resource context = context_->pp_resource(); | 383 GLuint shader = glCreateShader(type); |
| 312 GLuint shader = gles2_if_->CreateShader(context, type); | 384 GLint length = strlen(source) + 1; |
| 313 gles2_if_->ShaderSource(context, shader, 1, &source, &size); | 385 glShaderSource(shader, 1, &source, &length); |
| 314 gles2_if_->CompileShader(context, shader); | 386 glCompileShader(shader); |
| 315 gles2_if_->AttachShader(context, program, shader); | 387 glAttachShader(program, shader); |
| 316 gles2_if_->DeleteShader(context, shader); | 388 glDeleteShader(shader); |
| 317 } | 389 } |
| 318 | 390 |
| 319 void MediaStreamVideoDemoInstance::CreateYUVTextures() { | 391 void MediaStreamVideoDemoInstance::CreateTextures() { |
| 320 int32_t width = frame_size_.width(); | 392 int32_t width = frame_size_.width(); |
| 321 int32_t height = frame_size_.height(); | 393 int32_t height = frame_size_.height(); |
| 322 if (width == 0 || height == 0) | 394 if (width == 0 || height == 0) |
| 323 return; | 395 return; |
| 324 if (texture_y_) | 396 if (texture_y_) |
| 325 gles2_if_->DeleteTextures(context_->pp_resource(), 1, &texture_y_); | 397 glDeleteTextures(1, &texture_y_); |
| 326 if (texture_u_) | 398 if (texture_u_) |
| 327 gles2_if_->DeleteTextures(context_->pp_resource(), 1, &texture_u_); | 399 glDeleteTextures(1, &texture_u_); |
| 328 if (texture_v_) | 400 if (texture_v_) |
| 329 gles2_if_->DeleteTextures(context_->pp_resource(), 1, &texture_v_); | 401 glDeleteTextures(1, &texture_v_); |
| 330 texture_y_ = CreateTexture(width, height, 0); | 402 if (texture_rgb_) |
| 403 glDeleteTextures(1, &texture_rgb_); |
| 404 texture_y_ = CreateTexture(width, height, 0, false); |
| 331 | 405 |
| 332 width /= 2; | 406 texture_u_ = CreateTexture(width / 2, height / 2, 1, false); |
| 333 height /= 2; | 407 texture_v_ = CreateTexture(width / 2, height / 2, 2, false); |
| 334 texture_u_ = CreateTexture(width, height, 1); | 408 texture_rgb_ = CreateTexture(width, height, 3, true); |
| 335 texture_v_ = CreateTexture(width, height, 2); | 409 } |
| 410 |
| 411 void MediaStreamVideoDemoInstance::ConfigureTrack() { |
| 412 const int32_t attrib_list[] = { |
| 413 PP_MEDIASTREAMVIDEOTRACK_ATTRIB_FORMAT, attrib_format_, |
| 414 PP_MEDIASTREAMVIDEOTRACK_ATTRIB_WIDTH, attrib_width_, |
| 415 PP_MEDIASTREAMVIDEOTRACK_ATTRIB_HEIGHT, attrib_height_, |
| 416 PP_MEDIASTREAMVIDEOTRACK_ATTRIB_NONE |
| 417 }; |
| 418 video_track_.Configure(attrib_list, callback_factory_.NewCallback( |
| 419 &MediaStreamVideoDemoInstance::OnConfigure)); |
| 420 } |
| 421 |
| 422 void MediaStreamVideoDemoInstance::OnConfigure(int32_t result) { |
| 423 video_track_.GetFrame(callback_factory_.NewCallbackWithOutput( |
| 424 &MediaStreamVideoDemoInstance::OnGetFrame)); |
| 336 } | 425 } |
| 337 | 426 |
| 338 void MediaStreamVideoDemoInstance::OnGetFrame( | 427 void MediaStreamVideoDemoInstance::OnGetFrame( |
| 339 int32_t result, pp::VideoFrame frame) { | 428 int32_t result, pp::VideoFrame frame) { |
| 340 if (result != PP_OK) | 429 if (result != PP_OK) |
| 341 return; | 430 return; |
| 342 const char* data = static_cast<const char*>(frame.GetDataBuffer()); | 431 const char* data = static_cast<const char*>(frame.GetDataBuffer()); |
| 343 pp::Size size; | 432 pp::Size size; |
| 344 PP_DCHECK(frame.GetSize(&size)); | 433 frame.GetSize(&size); |
| 434 |
| 345 if (size != frame_size_) { | 435 if (size != frame_size_) { |
| 346 frame_size_ = size; | 436 frame_size_ = size; |
| 347 CreateYUVTextures(); | 437 CreateTextures(); |
| 348 } | 438 } |
| 349 | 439 |
| 440 is_bgra_ = (frame.GetFormat() == PP_VIDEOFRAME_FORMAT_BGRA); |
| 441 |
| 350 int32_t width = frame_size_.width(); | 442 int32_t width = frame_size_.width(); |
| 351 int32_t height = frame_size_.height(); | 443 int32_t height = frame_size_.height(); |
| 352 gles2_if_->ActiveTexture(context_->pp_resource(), GL_TEXTURE0); | 444 if (!is_bgra_) { |
| 353 gles2_if_->TexSubImage2D( | 445 glActiveTexture(GL_TEXTURE0); |
| 354 context_->pp_resource(), GL_TEXTURE_2D, 0, 0, 0, width, height, | 446 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, |
| 355 GL_LUMINANCE, GL_UNSIGNED_BYTE, data); | 447 GL_LUMINANCE, GL_UNSIGNED_BYTE, data); |
| 356 | 448 |
| 357 data += width * height; | 449 data += width * height; |
| 358 width /= 2; | 450 width /= 2; |
| 359 height /= 2; | 451 height /= 2; |
| 360 | 452 |
| 361 gles2_if_->ActiveTexture(context_->pp_resource(), GL_TEXTURE1); | 453 glActiveTexture(GL_TEXTURE1); |
| 362 gles2_if_->TexSubImage2D( | 454 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, |
| 363 context_->pp_resource(), GL_TEXTURE_2D, 0, 0, 0, width, height, | 455 GL_LUMINANCE, GL_UNSIGNED_BYTE, data); |
| 364 GL_LUMINANCE, GL_UNSIGNED_BYTE, data); | |
| 365 | 456 |
| 366 data += width * height; | 457 data += width * height; |
| 367 gles2_if_->ActiveTexture(context_->pp_resource(), GL_TEXTURE2); | 458 glActiveTexture(GL_TEXTURE2); |
| 368 gles2_if_->TexSubImage2D( | 459 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, |
| 369 context_->pp_resource(), GL_TEXTURE_2D, 0, 0, 0, width, height, | 460 GL_LUMINANCE, GL_UNSIGNED_BYTE, data); |
| 370 GL_LUMINANCE, GL_UNSIGNED_BYTE, data); | 461 } else { |
| 462 glActiveTexture(GL_TEXTURE3); |
| 463 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, |
| 464 GL_BGRA_EXT, GL_UNSIGNED_BYTE, data); |
| 465 } |
| 371 | 466 |
| 372 if (is_painting_) | 467 if (is_painting_) |
| 373 needs_paint_ = true; | 468 needs_paint_ = true; |
| 374 else | 469 else |
| 375 Render(); | 470 Render(); |
| 376 | 471 |
| 377 video_track_.RecycleFrame(frame); | 472 video_track_.RecycleFrame(frame); |
| 378 video_track_.GetFrame(callback_factory_.NewCallbackWithOutput( | 473 if (need_config_) { |
| 379 &MediaStreamVideoDemoInstance::OnGetFrame)); | 474 ConfigureTrack(); |
| 475 need_config_ = false; |
| 476 } else { |
| 477 video_track_.GetFrame(callback_factory_.NewCallbackWithOutput( |
| 478 &MediaStreamVideoDemoInstance::OnGetFrame)); |
| 479 } |
| 380 } | 480 } |
| 381 | 481 |
| 382 pp::Instance* MediaStreamVideoModule::CreateInstance(PP_Instance instance) { | 482 pp::Instance* MediaStreamVideoModule::CreateInstance(PP_Instance instance) { |
| 383 return new MediaStreamVideoDemoInstance(instance, this); | 483 return new MediaStreamVideoDemoInstance(instance, this); |
| 384 } | 484 } |
| 385 | 485 |
| 386 } // anonymous namespace | 486 } // anonymous namespace |
| 387 | 487 |
| 388 namespace pp { | 488 namespace pp { |
| 389 // Factory function for your specialization of the Module object. | 489 // Factory function for your specialization of the Module object. |
| 390 Module* CreateModule() { | 490 Module* CreateModule() { |
| 391 return new MediaStreamVideoModule(); | 491 return new MediaStreamVideoModule(); |
| 392 } | 492 } |
| 393 } // namespace pp | 493 } // namespace pp |
| OLD | NEW |