1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <string.h> 6 7 #include <iostream> 8 #include <sstream> 9 #include <list> 10 #include <map> 11 #include <set> 12 #include <vector> 13 14 #include "ppapi/c/pp_errors.h" 15 #include "ppapi/c/ppb_console.h" 16 #include "ppapi/c/ppb_opengles2.h" 17 #include "ppapi/cpp/dev/video_decoder_client_dev.h" 18 #include "ppapi/cpp/dev/video_decoder_dev.h" 19 #include "ppapi/cpp/graphics_3d.h" 20 #include "ppapi/cpp/graphics_3d_client.h" 21 #include "ppapi/cpp/instance.h" 22 #include "ppapi/cpp/module.h" 23 #include "ppapi/cpp/rect.h" 24 #include "ppapi/cpp/var.h" 25 #include "ppapi/examples/video_decode/testdata.h" 26 #include "ppapi/lib/gl/include/GLES2/gl2.h" 27 #include "ppapi/lib/gl/include/GLES2/gl2ext.h" 28 #include "ppapi/utility/completion_callback_factory.h" 29 30 // Use assert as a poor-man's CHECK, even in non-debug mode. 31 // Since <assert.h> redefines assert on every inclusion (it doesn't use 32 // include-guards), make sure this is the last file #include'd in this file. 33 #undef NDEBUG 34 #include <assert.h> 35 36 // Assert |context_| isn't holding any GL Errors. Done as a macro instead of a 37 // function to preserve line number information in the failure message. 38 #define assertNoGLError() \ 39 assert(!gles2_if_->GetError(context_->pp_resource())); 40 41 namespace { 42 43 struct PictureBufferInfo { 44 PP_PictureBuffer_Dev buffer; 45 GLenum texture_target; 46 }; 47 48 struct Shader { 49 Shader() : program(0), 50 texcoord_scale_location(0) {} 51 52 GLuint program; 53 GLint texcoord_scale_location; 54 }; 55 56 class VideoDecodeDemoInstance : public pp::Instance, 57 public pp::Graphics3DClient, 58 public pp::VideoDecoderClient_Dev { 59 public: 60 VideoDecodeDemoInstance(PP_Instance instance, pp::Module* module); 61 virtual ~VideoDecodeDemoInstance(); 62 63 // pp::Instance implementation (see PPP_Instance). 64 virtual void DidChangeView(const pp::Rect& position, 65 const pp::Rect& clip_ignored); 66 67 // pp::Graphics3DClient implementation. 68 virtual void Graphics3DContextLost() { 69 // TODO(vrk/fischman): Properly reset after a lost graphics context. In 70 // particular need to delete context_ and re-create textures. 71 // Probably have to recreate the decoder from scratch, because old textures 72 // can still be outstanding in the decoder! 73 assert(false && "Unexpectedly lost graphics context"); 74 } 75 76 // pp::VideoDecoderClient_Dev implementation. 77 virtual void ProvidePictureBuffers( 78 PP_Resource decoder, 79 uint32_t req_num_of_bufs, 80 const PP_Size& dimensions, 81 uint32_t texture_target); 82 virtual void DismissPictureBuffer(PP_Resource decoder, 83 int32_t picture_buffer_id); 84 virtual void PictureReady(PP_Resource decoder, const PP_Picture_Dev& picture); 85 virtual void NotifyError(PP_Resource decoder, PP_VideoDecodeError_Dev error); 86 87 private: 88 enum { kNumConcurrentDecodes = 7, 89 kNumDecoders = 2 }; // Baked into viewport rendering. 90 91 // A single decoder's client interface. 92 class DecoderClient { 93 public: 94 DecoderClient(VideoDecodeDemoInstance* gles2, 95 pp::VideoDecoder_Dev* decoder); 96 ~DecoderClient(); 97 98 void DecodeNextNALUs(); 99 100 // Per-decoder implementation of part of pp::VideoDecoderClient_Dev. 101 void ProvidePictureBuffers( 102 uint32_t req_num_of_bufs, 103 PP_Size dimensions, 104 uint32_t texture_target); 105 void DismissPictureBuffer(int32_t picture_buffer_id); 106 107 const PictureBufferInfo& GetPictureBufferInfoById(int id); 108 pp::VideoDecoder_Dev* decoder() { return decoder_; } 109 110 private: 111 void DecodeNextNALU(); 112 static void GetNextNALUBoundary(size_t start_pos, size_t* end_pos); 113 void DecoderBitstreamDone(int32_t result, int bitstream_buffer_id); 114 void DecoderFlushDone(int32_t result); 115 116 VideoDecodeDemoInstance* gles2_; 117 pp::VideoDecoder_Dev* decoder_; 118 pp::CompletionCallbackFactory<DecoderClient> callback_factory_; 119 int next_picture_buffer_id_; 120 int next_bitstream_buffer_id_; 121 size_t encoded_data_next_pos_to_decode_; 122 std::set<int> bitstream_ids_at_decoder_; 123 // Map of texture buffers indexed by buffer id. 124 typedef std::map<int, PictureBufferInfo> PictureBufferMap; 125 PictureBufferMap picture_buffers_by_id_; 126 // Map of bitstream buffers indexed by id. 127 typedef std::map<int, pp::Buffer_Dev*> BitstreamBufferMap; 128 BitstreamBufferMap bitstream_buffers_by_id_; 129 }; 130 131 // Initialize Video Decoders. 132 void InitializeDecoders(); 133 134 // GL-related functions. 135 void InitGL(); 136 GLuint CreateTexture(int32_t width, int32_t height, GLenum texture_target); 137 void CreateGLObjects(); 138 void Create2DProgramOnce(); 139 void CreateRectangleARBProgramOnce(); 140 Shader CreateProgram(const char* vertex_shader, 141 const char* fragment_shader); 142 void CreateShader(GLuint program, GLenum type, const char* source, int size); 143 void DeleteTexture(GLuint id); 144 void PaintFinished(int32_t result, PP_Resource decoder, 145 int picture_buffer_id); 146 147 // Log an error to the developer console and stderr (though the latter may be 148 // closed due to sandboxing or blackholed for other reasons) by creating a 149 // temporary of this type and streaming to it. Example usage: 150 // LogError(this).s() << "Hello world: " << 42; 151 class LogError { 152 public: 153 LogError(VideoDecodeDemoInstance* demo) : demo_(demo) {} 154 ~LogError() { 155 const std::string& msg = stream_.str(); 156 demo_->console_if_->Log(demo_->pp_instance(), PP_LOGLEVEL_ERROR, 157 pp::Var(msg).pp_var()); 158 std::cerr << msg << std::endl; 159 } 160 // Impl note: it would have been nicer to have LogError derive from 161 // std::ostringstream so that it can be streamed to directly, but lookup 162 // rules turn streamed string literals to hex pointers on output. 163 std::ostringstream& s() { return stream_; } 164 private: 165 VideoDecodeDemoInstance* demo_; // Unowned. 166 std::ostringstream stream_; 167 }; 168 169 pp::Size plugin_size_; 170 bool is_painting_; 171 // When decode outpaces render, we queue up decoded pictures for later 172 // painting. Elements are <decoder,picture>. 173 std::list<std::pair<PP_Resource, PP_Picture_Dev> > pictures_pending_paint_; 174 int num_frames_rendered_; 175 PP_TimeTicks first_frame_delivered_ticks_; 176 PP_TimeTicks last_swap_request_ticks_; 177 PP_TimeTicks swap_ticks_; 178 pp::CompletionCallbackFactory<VideoDecodeDemoInstance> callback_factory_; 179 180 // Unowned pointers. 181 const PPB_Console* console_if_; 182 const PPB_Core* core_if_; 183 const PPB_OpenGLES2* gles2_if_; 184 185 // Owned data. 186 pp::Graphics3D* context_; 187 typedef std::map<int, DecoderClient*> Decoders; 188 Decoders video_decoders_; 189 190 // Shader program to draw GL_TEXTURE_2D target. 191 Shader shader_2d_; 192 // Shader program to draw GL_TEXTURE_RECTANGLE_ARB target. 193 Shader shader_rectangle_arb_; 194 }; 195 196 VideoDecodeDemoInstance::DecoderClient::DecoderClient( 197 VideoDecodeDemoInstance* gles2, pp::VideoDecoder_Dev* decoder) 198 : gles2_(gles2), decoder_(decoder), callback_factory_(this), 199 next_picture_buffer_id_(0), 200 next_bitstream_buffer_id_(0), encoded_data_next_pos_to_decode_(0) { 201 } 202 203 VideoDecodeDemoInstance::DecoderClient::~DecoderClient() { 204 delete decoder_; 205 decoder_ = NULL; 206 207 for (BitstreamBufferMap::iterator it = bitstream_buffers_by_id_.begin(); 208 it != bitstream_buffers_by_id_.end(); ++it) { 209 delete it->second; 210 } 211 bitstream_buffers_by_id_.clear(); 212 213 for (PictureBufferMap::iterator it = picture_buffers_by_id_.begin(); 214 it != picture_buffers_by_id_.end(); ++it) { 215 gles2_->DeleteTexture(it->second.buffer.texture_id); 216 } 217 picture_buffers_by_id_.clear(); 218 } 219 220 VideoDecodeDemoInstance::VideoDecodeDemoInstance(PP_Instance instance, 221 pp::Module* module) 222 : pp::Instance(instance), pp::Graphics3DClient(this), 223 pp::VideoDecoderClient_Dev(this), 224 is_painting_(false), 225 num_frames_rendered_(0), 226 first_frame_delivered_ticks_(-1), 227 swap_ticks_(0), 228 callback_factory_(this), 229 context_(NULL) { 230 assert((console_if_ = static_cast<const PPB_Console*>( 231 module->GetBrowserInterface(PPB_CONSOLE_INTERFACE)))); 232 assert((core_if_ = static_cast<const PPB_Core*>( 233 module->GetBrowserInterface(PPB_CORE_INTERFACE)))); 234 assert((gles2_if_ = static_cast<const PPB_OpenGLES2*>( 235 module->GetBrowserInterface(PPB_OPENGLES2_INTERFACE)))); 236 } 237 238 VideoDecodeDemoInstance::~VideoDecodeDemoInstance() { 239 if (shader_2d_.program) 240 gles2_if_->DeleteProgram(context_->pp_resource(), shader_2d_.program); 241 if (shader_rectangle_arb_.program) { 242 gles2_if_->DeleteProgram( 243 context_->pp_resource(), shader_rectangle_arb_.program); 244 } 245 246 for (Decoders::iterator it = video_decoders_.begin(); 247 it != video_decoders_.end(); ++it) { 248 delete it->second; 249 } 250 video_decoders_.clear(); 251 delete context_; 252 } 253 254 void VideoDecodeDemoInstance::DidChangeView( 255 const pp::Rect& position, const pp::Rect& clip_ignored) { 256 if (position.width() == 0 || position.height() == 0) 257 return; 258 if (plugin_size_.width()) { 259 assert(position.size() == plugin_size_); 260 return; 261 } 262 plugin_size_ = position.size(); 263 264 // Initialize graphics. 265 InitGL(); 266 InitializeDecoders(); 267 } 268 269 void VideoDecodeDemoInstance::InitializeDecoders() { 270 assert(video_decoders_.empty()); 271 for (int i = 0; i < kNumDecoders; ++i) { 272 DecoderClient* client = new DecoderClient( 273 this, new pp::VideoDecoder_Dev( 274 this, *context_, PP_VIDEODECODER_H264PROFILE_MAIN)); 275 assert(!client->decoder()->is_null()); 276 assert(video_decoders_.insert(std::make_pair( 277 client->decoder()->pp_resource(), client)).second); 278 client->DecodeNextNALUs(); 279 } 280 } 281 282 void VideoDecodeDemoInstance::DecoderClient::DecoderBitstreamDone( 283 int32_t result, int bitstream_buffer_id) { 284 assert(bitstream_ids_at_decoder_.erase(bitstream_buffer_id) == 1); 285 BitstreamBufferMap::iterator it = 286 bitstream_buffers_by_id_.find(bitstream_buffer_id); 287 assert(it != bitstream_buffers_by_id_.end()); 288 delete it->second; 289 bitstream_buffers_by_id_.erase(it); 290 DecodeNextNALUs(); 291 } 292 293 void VideoDecodeDemoInstance::DecoderClient::DecoderFlushDone(int32_t result) { 294 assert(result == PP_OK); 295 // Check that each bitstream buffer ID we handed to the decoder got handed 296 // back to us. 297 assert(bitstream_ids_at_decoder_.empty()); 298 delete decoder_; 299 decoder_ = NULL; 300 } 301 302 static bool LookingAtNAL(const unsigned char* encoded, size_t pos) { 303 return pos + 3 < kDataLen && 304 encoded[pos] == 0 && encoded[pos + 1] == 0 && 305 encoded[pos + 2] == 0 && encoded[pos + 3] == 1; 306 } 307 308 void VideoDecodeDemoInstance::DecoderClient::GetNextNALUBoundary( 309 size_t start_pos, size_t* end_pos) { 310 assert(LookingAtNAL(kData, start_pos)); 311 *end_pos = start_pos; 312 *end_pos += 4; 313 while (*end_pos + 3 < kDataLen && 314 !LookingAtNAL(kData, *end_pos)) { 315 ++*end_pos; 316 } 317 if (*end_pos + 3 >= kDataLen) { 318 *end_pos = kDataLen; 319 return; 320 } 321 } 322 323 void VideoDecodeDemoInstance::DecoderClient::DecodeNextNALUs() { 324 while (encoded_data_next_pos_to_decode_ <= kDataLen && 325 bitstream_ids_at_decoder_.size() < kNumConcurrentDecodes) { 326 DecodeNextNALU(); 327 } 328 } 329 330 void VideoDecodeDemoInstance::DecoderClient::DecodeNextNALU() { 331 if (encoded_data_next_pos_to_decode_ == kDataLen) { 332 ++encoded_data_next_pos_to_decode_; 333 pp::CompletionCallback cb = callback_factory_.NewCallback( 334 &VideoDecodeDemoInstance::DecoderClient::DecoderFlushDone); 335 decoder_->Flush(cb); 336 return; 337 } 338 size_t start_pos = encoded_data_next_pos_to_decode_; 339 size_t end_pos; 340 GetNextNALUBoundary(start_pos, &end_pos); 341 pp::Buffer_Dev* buffer = new pp::Buffer_Dev(gles2_, end_pos - start_pos); 342 PP_VideoBitstreamBuffer_Dev bitstream_buffer; 343 int id = ++next_bitstream_buffer_id_; 344 bitstream_buffer.id = id; 345 bitstream_buffer.size = end_pos - start_pos; 346 bitstream_buffer.data = buffer->pp_resource(); 347 memcpy(buffer->data(), kData + start_pos, end_pos - start_pos); 348 assert(bitstream_buffers_by_id_.insert(std::make_pair(id, buffer)).second); 349 350 pp::CompletionCallback cb = 351 callback_factory_.NewCallback( 352 &VideoDecodeDemoInstance::DecoderClient::DecoderBitstreamDone, id); 353 assert(bitstream_ids_at_decoder_.insert(id).second); 354 encoded_data_next_pos_to_decode_ = end_pos; 355 decoder_->Decode(bitstream_buffer, cb); 356 } 357 358 void VideoDecodeDemoInstance::ProvidePictureBuffers(PP_Resource decoder, 359 uint32_t req_num_of_bufs, 360 const PP_Size& dimensions, 361 uint32_t texture_target) { 362 DecoderClient* client = video_decoders_[decoder]; 363 assert(client); 364 client->ProvidePictureBuffers(req_num_of_bufs, dimensions, texture_target); 365 } 366 367 void VideoDecodeDemoInstance::DecoderClient::ProvidePictureBuffers( 368 uint32_t req_num_of_bufs, 369 PP_Size dimensions, 370 uint32_t texture_target) { 371 std::vector<PP_PictureBuffer_Dev> buffers; 372 for (uint32_t i = 0; i < req_num_of_bufs; ++i) { 373 PictureBufferInfo info; 374 info.buffer.size = dimensions; 375 info.texture_target = texture_target; 376 info.buffer.texture_id = gles2_->CreateTexture( 377 dimensions.width, dimensions.height, info.texture_target); 378 int id = ++next_picture_buffer_id_; 379 info.buffer.id = id; 380 buffers.push_back(info.buffer); 381 assert(picture_buffers_by_id_.insert(std::make_pair(id, info)).second); 382 } 383 decoder_->AssignPictureBuffers(buffers); 384 } 385 386 const PictureBufferInfo& 387 VideoDecodeDemoInstance::DecoderClient::GetPictureBufferInfoById( 388 int id) { 389 PictureBufferMap::iterator it = picture_buffers_by_id_.find(id); 390 assert(it != picture_buffers_by_id_.end()); 391 return it->second; 392 } 393 394 void VideoDecodeDemoInstance::DismissPictureBuffer(PP_Resource decoder, 395 int32_t picture_buffer_id) { 396 DecoderClient* client = video_decoders_[decoder]; 397 assert(client); 398 client->DismissPictureBuffer(picture_buffer_id); 399 } 400 401 void VideoDecodeDemoInstance::DecoderClient::DismissPictureBuffer( 402 int32_t picture_buffer_id) { 403 gles2_->DeleteTexture(GetPictureBufferInfoById( 404 picture_buffer_id).buffer.texture_id); 405 picture_buffers_by_id_.erase(picture_buffer_id); 406 } 407 408 void VideoDecodeDemoInstance::PictureReady(PP_Resource decoder, 409 const PP_Picture_Dev& picture) { 410 if (first_frame_delivered_ticks_ == -1) 411 assert((first_frame_delivered_ticks_ = core_if_->GetTimeTicks()) != -1); 412 if (is_painting_) { 413 pictures_pending_paint_.push_back(std::make_pair(decoder, picture)); 414 return; 415 } 416 DecoderClient* client = video_decoders_[decoder]; 417 assert(client); 418 const PictureBufferInfo& info = 419 client->GetPictureBufferInfoById(picture.picture_buffer_id); 420 assert(!is_painting_); 421 is_painting_ = true; 422 int x = 0; 423 int y = 0; 424 if (client != video_decoders_.begin()->second) { 425 x = plugin_size_.width() / kNumDecoders; 426 y = plugin_size_.height() / kNumDecoders; 427 } 428 429 if (info.texture_target == GL_TEXTURE_2D) { 430 Create2DProgramOnce(); 431 gles2_if_->UseProgram(context_->pp_resource(), shader_2d_.program); 432 gles2_if_->Uniform2f( 433 context_->pp_resource(), shader_2d_.texcoord_scale_location, 1.0, 1.0); 434 } else { 435 assert(info.texture_target == GL_TEXTURE_RECTANGLE_ARB); 436 CreateRectangleARBProgramOnce(); 437 gles2_if_->UseProgram( 438 context_->pp_resource(), shader_rectangle_arb_.program); 439 gles2_if_->Uniform2f(context_->pp_resource(), 440 shader_rectangle_arb_.texcoord_scale_location, 441 info.buffer.size.width, 442 info.buffer.size.height); 443 } 444 445 gles2_if_->Viewport(context_->pp_resource(), x, y, 446 plugin_size_.width() / kNumDecoders, 447 plugin_size_.height() / kNumDecoders); 448 gles2_if_->ActiveTexture(context_->pp_resource(), GL_TEXTURE0); 449 gles2_if_->BindTexture( 450 context_->pp_resource(), info.texture_target, info.buffer.texture_id); 451 gles2_if_->DrawArrays(context_->pp_resource(), GL_TRIANGLE_STRIP, 0, 4); 452 453 gles2_if_->UseProgram(context_->pp_resource(), 0); 454 455 pp::CompletionCallback cb = 456 callback_factory_.NewCallback( 457 &VideoDecodeDemoInstance::PaintFinished, decoder, info.buffer.id); 458 last_swap_request_ticks_ = core_if_->GetTimeTicks(); 459 assert(context_->SwapBuffers(cb) == PP_OK_COMPLETIONPENDING); 460 } 461 462 void VideoDecodeDemoInstance::NotifyError(PP_Resource decoder, 463 PP_VideoDecodeError_Dev error) { 464 LogError(this).s() << "Received error: " << error; 465 assert(false && "Unexpected error; see stderr for details"); 466 } 467 468 // This object is the global object representing this plugin library as long 469 // as it is loaded. 470 class VideoDecodeDemoModule : public pp::Module { 471 public: 472 VideoDecodeDemoModule() : pp::Module() {} 473 virtual ~VideoDecodeDemoModule() {} 474 475 virtual pp::Instance* CreateInstance(PP_Instance instance) { 476 return new VideoDecodeDemoInstance(instance, this); 477 } 478 }; 479 480 void VideoDecodeDemoInstance::InitGL() { 481 assert(plugin_size_.width() && plugin_size_.height()); 482 is_painting_ = false; 483 484 assert(!context_); 485 int32_t context_attributes[] = { 486 PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8, 487 PP_GRAPHICS3DATTRIB_BLUE_SIZE, 8, 488 PP_GRAPHICS3DATTRIB_GREEN_SIZE, 8, 489 PP_GRAPHICS3DATTRIB_RED_SIZE, 8, 490 PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 0, 491 PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 0, 492 PP_GRAPHICS3DATTRIB_SAMPLES, 0, 493 PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, 0, 494 PP_GRAPHICS3DATTRIB_WIDTH, plugin_size_.width(), 495 PP_GRAPHICS3DATTRIB_HEIGHT, plugin_size_.height(), 496 PP_GRAPHICS3DATTRIB_NONE, 497 }; 498 context_ = new pp::Graphics3D(this, context_attributes); 499 assert(!context_->is_null()); 500 assert(BindGraphics(*context_)); 501 502 // Clear color bit. 503 gles2_if_->ClearColor(context_->pp_resource(), 1, 0, 0, 1); 504 gles2_if_->Clear(context_->pp_resource(), GL_COLOR_BUFFER_BIT); 505 506 assertNoGLError(); 507 508 CreateGLObjects(); 509 } 510 511 void VideoDecodeDemoInstance::PaintFinished(int32_t result, PP_Resource decoder, 512 int picture_buffer_id) { 513 assert(result == PP_OK); 514 swap_ticks_ += core_if_->GetTimeTicks() - last_swap_request_ticks_; 515 is_painting_ = false; 516 ++num_frames_rendered_; 517 if (num_frames_rendered_ % 50 == 0) { 518 double elapsed = core_if_->GetTimeTicks() - first_frame_delivered_ticks_; 519 double fps = (elapsed > 0) ? num_frames_rendered_ / elapsed : 1000; 520 double ms_per_swap = (swap_ticks_ * 1e3) / num_frames_rendered_; 521 LogError(this).s() << "Rendered frames: " << num_frames_rendered_ 522 << ", fps: " << fps << ", with average ms/swap of: " 523 << ms_per_swap; 524 } 525 DecoderClient* client = video_decoders_[decoder]; 526 if (client && client->decoder()) 527 client->decoder()->ReusePictureBuffer(picture_buffer_id); 528 if (!pictures_pending_paint_.empty()) { 529 std::pair<PP_Resource, PP_Picture_Dev> decoder_picture = 530 pictures_pending_paint_.front(); 531 pictures_pending_paint_.pop_front(); 532 PictureReady(decoder_picture.first, decoder_picture.second); 533 } 534 } 535 536 GLuint VideoDecodeDemoInstance::CreateTexture(int32_t width, 537 int32_t height, 538 GLenum texture_target) { 539 GLuint texture_id; 540 gles2_if_->GenTextures(context_->pp_resource(), 1, &texture_id); 541 assertNoGLError(); 542 // Assign parameters. 543 gles2_if_->ActiveTexture(context_->pp_resource(), GL_TEXTURE0); 544 gles2_if_->BindTexture(context_->pp_resource(), texture_target, texture_id); 545 gles2_if_->TexParameteri( 546 context_->pp_resource(), texture_target, GL_TEXTURE_MIN_FILTER, 547 GL_NEAREST); 548 gles2_if_->TexParameteri( 549 context_->pp_resource(), texture_target, GL_TEXTURE_MAG_FILTER, 550 GL_NEAREST); 551 gles2_if_->TexParameterf( 552 context_->pp_resource(), texture_target, GL_TEXTURE_WRAP_S, 553 GL_CLAMP_TO_EDGE); 554 gles2_if_->TexParameterf( 555 context_->pp_resource(), texture_target, GL_TEXTURE_WRAP_T, 556 GL_CLAMP_TO_EDGE); 557 558 if (texture_target == GL_TEXTURE_2D) { 559 gles2_if_->TexImage2D( 560 context_->pp_resource(), texture_target, 0, GL_RGBA, width, height, 0, 561 GL_RGBA, GL_UNSIGNED_BYTE, NULL); 562 } 563 assertNoGLError(); 564 return texture_id; 565 } 566 567 void VideoDecodeDemoInstance::DeleteTexture(GLuint id) { 568 gles2_if_->DeleteTextures(context_->pp_resource(), 1, &id); 569 } 570 571 void VideoDecodeDemoInstance::CreateGLObjects() { 572 // Assign vertex positions and texture coordinates to buffers for use in 573 // shader program. 574 static const float kVertices[] = { 575 -1, 1, -1, -1, 1, 1, 1, -1, // Position coordinates. 576 0, 1, 0, 0, 1, 1, 1, 0, // Texture coordinates. 577 }; 578 579 GLuint buffer; 580 gles2_if_->GenBuffers(context_->pp_resource(), 1, &buffer); 581 gles2_if_->BindBuffer(context_->pp_resource(), GL_ARRAY_BUFFER, buffer); 582 583 gles2_if_->BufferData(context_->pp_resource(), GL_ARRAY_BUFFER, 584 sizeof(kVertices), kVertices, GL_STATIC_DRAW); 585 assertNoGLError(); 586 } 587 588 static const char kVertexShader[] = 589 "varying vec2 v_texCoord; \n" 590 "attribute vec4 a_position; \n" 591 "attribute vec2 a_texCoord; \n" 592 "uniform vec2 v_scale; \n" 593 "void main() \n" 594 "{ \n" 595 " v_texCoord = v_scale * a_texCoord; \n" 596 " gl_Position = a_position; \n" 597 "}"; 598 599 void VideoDecodeDemoInstance::Create2DProgramOnce() { 600 if (shader_2d_.program) 601 return; 602 static const char kFragmentShader2D[] = 603 "precision mediump float; \n" 604 "varying vec2 v_texCoord; \n" 605 "uniform sampler2D s_texture; \n" 606 "void main() \n" 607 "{" 608 " gl_FragColor = texture2D(s_texture, v_texCoord); \n" 609 "}"; 610 shader_2d_ = CreateProgram(kVertexShader, kFragmentShader2D); 611 assertNoGLError(); 612 } 613 614 void VideoDecodeDemoInstance::CreateRectangleARBProgramOnce() { 615 if (shader_rectangle_arb_.program) 616 return; 617 static const char kFragmentShaderRectangle[] = 618 "#extension GL_ARB_texture_rectangle : require\n" 619 "precision mediump float; \n" 620 "varying vec2 v_texCoord; \n" 621 "uniform sampler2DRect s_texture; \n" 622 "void main() \n" 623 "{" 624 " gl_FragColor = texture2DRect(s_texture, v_texCoord).rgba; \n" 625 "}"; 626 shader_rectangle_arb_ = 627 CreateProgram(kVertexShader, kFragmentShaderRectangle); 628 } 629 630 Shader VideoDecodeDemoInstance::CreateProgram(const char* vertex_shader, 631 const char* fragment_shader) { 632 Shader shader; 633 634 // Create shader program. 635 shader.program = gles2_if_->CreateProgram(context_->pp_resource()); 636 CreateShader(shader.program, GL_VERTEX_SHADER, vertex_shader, 637 strlen(vertex_shader)); 638 CreateShader(shader.program, GL_FRAGMENT_SHADER, fragment_shader, 639 strlen(fragment_shader)); 640 gles2_if_->LinkProgram(context_->pp_resource(), shader.program); 641 gles2_if_->UseProgram(context_->pp_resource(), shader.program); 642 gles2_if_->Uniform1i( 643 context_->pp_resource(), 644 gles2_if_->GetUniformLocation( 645 context_->pp_resource(), shader.program, "s_texture"), 0); 646 assertNoGLError(); 647 648 shader.texcoord_scale_location = gles2_if_->GetUniformLocation( 649 context_->pp_resource(), shader.program, "v_scale"); 650 651 GLint pos_location = gles2_if_->GetAttribLocation( 652 context_->pp_resource(), shader.program, "a_position"); 653 GLint tc_location = gles2_if_->GetAttribLocation( 654 context_->pp_resource(), shader.program, "a_texCoord"); 655 assertNoGLError(); 656 657 gles2_if_->EnableVertexAttribArray(context_->pp_resource(), pos_location); 658 gles2_if_->VertexAttribPointer(context_->pp_resource(), pos_location, 2, 659 GL_FLOAT, GL_FALSE, 0, 0); 660 gles2_if_->EnableVertexAttribArray(context_->pp_resource(), tc_location); 661 gles2_if_->VertexAttribPointer( 662 context_->pp_resource(), tc_location, 2, GL_FLOAT, GL_FALSE, 0, 663 static_cast<float*>(0) + 8); // Skip position coordinates. 664 665 gles2_if_->UseProgram(context_->pp_resource(), 0); 666 assertNoGLError(); 667 return shader; 668 } 669 670 void VideoDecodeDemoInstance::CreateShader( 671 GLuint program, GLenum type, const char* source, int size) { 672 GLuint shader = gles2_if_->CreateShader(context_->pp_resource(), type); 673 gles2_if_->ShaderSource(context_->pp_resource(), shader, 1, &source, &size); 674 gles2_if_->CompileShader(context_->pp_resource(), shader); 675 gles2_if_->AttachShader(context_->pp_resource(), program, shader); 676 gles2_if_->DeleteShader(context_->pp_resource(), shader); 677 } 678 } // anonymous namespace 679 680 namespace pp { 681 // Factory function for your specialization of the Module object. 682 Module* CreateModule() { 683 return new VideoDecodeDemoModule(); 684 } 685 } // namespace pp 686