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 41namespace { 42 43struct PictureBufferInfo { 44 PP_PictureBuffer_Dev buffer; 45 GLenum texture_target; 46}; 47 48struct Shader { 49 Shader() : program(0), 50 texcoord_scale_location(0) {} 51 52 GLuint program; 53 GLint texcoord_scale_location; 54}; 55 56class 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 196VideoDecodeDemoInstance::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 203VideoDecodeDemoInstance::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 220VideoDecodeDemoInstance::VideoDecodeDemoInstance(PP_Instance instance, 221 pp::Module* module) 222 : pp::Instance(instance), pp::Graphics3DClient(this), 223 pp::VideoDecoderClient_Dev(this), 224 num_frames_rendered_(0), 225 first_frame_delivered_ticks_(-1), 226 swap_ticks_(0), 227 callback_factory_(this), 228 context_(NULL) { 229 assert((console_if_ = static_cast<const PPB_Console*>( 230 module->GetBrowserInterface(PPB_CONSOLE_INTERFACE)))); 231 assert((core_if_ = static_cast<const PPB_Core*>( 232 module->GetBrowserInterface(PPB_CORE_INTERFACE)))); 233 assert((gles2_if_ = static_cast<const PPB_OpenGLES2*>( 234 module->GetBrowserInterface(PPB_OPENGLES2_INTERFACE)))); 235} 236 237VideoDecodeDemoInstance::~VideoDecodeDemoInstance() { 238 if (shader_2d_.program) 239 gles2_if_->DeleteProgram(context_->pp_resource(), shader_2d_.program); 240 if (shader_rectangle_arb_.program) { 241 gles2_if_->DeleteProgram( 242 context_->pp_resource(), shader_rectangle_arb_.program); 243 } 244 245 for (Decoders::iterator it = video_decoders_.begin(); 246 it != video_decoders_.end(); ++it) { 247 delete it->second; 248 } 249 video_decoders_.clear(); 250 delete context_; 251} 252 253void VideoDecodeDemoInstance::DidChangeView( 254 const pp::Rect& position, const pp::Rect& clip_ignored) { 255 if (position.width() == 0 || position.height() == 0) 256 return; 257 if (plugin_size_.width()) { 258 assert(position.size() == plugin_size_); 259 return; 260 } 261 plugin_size_ = position.size(); 262 263 // Initialize graphics. 264 InitGL(); 265 InitializeDecoders(); 266} 267 268void VideoDecodeDemoInstance::InitializeDecoders() { 269 assert(video_decoders_.empty()); 270 for (int i = 0; i < kNumDecoders; ++i) { 271 DecoderClient* client = new DecoderClient( 272 this, new pp::VideoDecoder_Dev( 273 this, *context_, PP_VIDEODECODER_H264PROFILE_MAIN)); 274 assert(!client->decoder()->is_null()); 275 assert(video_decoders_.insert(std::make_pair( 276 client->decoder()->pp_resource(), client)).second); 277 client->DecodeNextNALUs(); 278 } 279} 280 281void VideoDecodeDemoInstance::DecoderClient::DecoderBitstreamDone( 282 int32_t result, int bitstream_buffer_id) { 283 assert(bitstream_ids_at_decoder_.erase(bitstream_buffer_id) == 1); 284 BitstreamBufferMap::iterator it = 285 bitstream_buffers_by_id_.find(bitstream_buffer_id); 286 assert(it != bitstream_buffers_by_id_.end()); 287 delete it->second; 288 bitstream_buffers_by_id_.erase(it); 289 DecodeNextNALUs(); 290} 291 292void VideoDecodeDemoInstance::DecoderClient::DecoderFlushDone(int32_t result) { 293 assert(result == PP_OK); 294 // Check that each bitstream buffer ID we handed to the decoder got handed 295 // back to us. 296 assert(bitstream_ids_at_decoder_.empty()); 297 delete decoder_; 298 decoder_ = NULL; 299} 300 301static bool LookingAtNAL(const unsigned char* encoded, size_t pos) { 302 return pos + 3 < kDataLen && 303 encoded[pos] == 0 && encoded[pos + 1] == 0 && 304 encoded[pos + 2] == 0 && encoded[pos + 3] == 1; 305} 306 307void VideoDecodeDemoInstance::DecoderClient::GetNextNALUBoundary( 308 size_t start_pos, size_t* end_pos) { 309 assert(LookingAtNAL(kData, start_pos)); 310 *end_pos = start_pos; 311 *end_pos += 4; 312 while (*end_pos + 3 < kDataLen && 313 !LookingAtNAL(kData, *end_pos)) { 314 ++*end_pos; 315 } 316 if (*end_pos + 3 >= kDataLen) { 317 *end_pos = kDataLen; 318 return; 319 } 320} 321 322void VideoDecodeDemoInstance::DecoderClient::DecodeNextNALUs() { 323 while (encoded_data_next_pos_to_decode_ <= kDataLen && 324 bitstream_ids_at_decoder_.size() < kNumConcurrentDecodes) { 325 DecodeNextNALU(); 326 } 327} 328 329void VideoDecodeDemoInstance::DecoderClient::DecodeNextNALU() { 330 if (encoded_data_next_pos_to_decode_ == kDataLen) { 331 ++encoded_data_next_pos_to_decode_; 332 pp::CompletionCallback cb = callback_factory_.NewCallback( 333 &VideoDecodeDemoInstance::DecoderClient::DecoderFlushDone); 334 decoder_->Flush(cb); 335 return; 336 } 337 size_t start_pos = encoded_data_next_pos_to_decode_; 338 size_t end_pos; 339 GetNextNALUBoundary(start_pos, &end_pos); 340 pp::Buffer_Dev* buffer = new pp::Buffer_Dev(gles2_, end_pos - start_pos); 341 PP_VideoBitstreamBuffer_Dev bitstream_buffer; 342 int id = ++next_bitstream_buffer_id_; 343 bitstream_buffer.id = id; 344 bitstream_buffer.size = end_pos - start_pos; 345 bitstream_buffer.data = buffer->pp_resource(); 346 memcpy(buffer->data(), kData + start_pos, end_pos - start_pos); 347 assert(bitstream_buffers_by_id_.insert(std::make_pair(id, buffer)).second); 348 349 pp::CompletionCallback cb = 350 callback_factory_.NewCallback( 351 &VideoDecodeDemoInstance::DecoderClient::DecoderBitstreamDone, id); 352 assert(bitstream_ids_at_decoder_.insert(id).second); 353 encoded_data_next_pos_to_decode_ = end_pos; 354 decoder_->Decode(bitstream_buffer, cb); 355} 356 357void VideoDecodeDemoInstance::ProvidePictureBuffers(PP_Resource decoder, 358 uint32_t req_num_of_bufs, 359 const PP_Size& dimensions, 360 uint32_t texture_target) { 361 DecoderClient* client = video_decoders_[decoder]; 362 assert(client); 363 client->ProvidePictureBuffers(req_num_of_bufs, dimensions, texture_target); 364} 365 366void VideoDecodeDemoInstance::DecoderClient::ProvidePictureBuffers( 367 uint32_t req_num_of_bufs, 368 PP_Size dimensions, 369 uint32_t texture_target) { 370 std::vector<PP_PictureBuffer_Dev> buffers; 371 for (uint32_t i = 0; i < req_num_of_bufs; ++i) { 372 PictureBufferInfo info; 373 info.buffer.size = dimensions; 374 info.texture_target = texture_target; 375 info.buffer.texture_id = gles2_->CreateTexture( 376 dimensions.width, dimensions.height, info.texture_target); 377 int id = ++next_picture_buffer_id_; 378 info.buffer.id = id; 379 buffers.push_back(info.buffer); 380 assert(picture_buffers_by_id_.insert(std::make_pair(id, info)).second); 381 } 382 decoder_->AssignPictureBuffers(buffers); 383} 384 385const PictureBufferInfo& 386VideoDecodeDemoInstance::DecoderClient::GetPictureBufferInfoById( 387 int id) { 388 PictureBufferMap::iterator it = picture_buffers_by_id_.find(id); 389 assert(it != picture_buffers_by_id_.end()); 390 return it->second; 391} 392 393void VideoDecodeDemoInstance::DismissPictureBuffer(PP_Resource decoder, 394 int32_t picture_buffer_id) { 395 DecoderClient* client = video_decoders_[decoder]; 396 assert(client); 397 client->DismissPictureBuffer(picture_buffer_id); 398} 399 400void VideoDecodeDemoInstance::DecoderClient::DismissPictureBuffer( 401 int32_t picture_buffer_id) { 402 gles2_->DeleteTexture(GetPictureBufferInfoById( 403 picture_buffer_id).buffer.texture_id); 404 picture_buffers_by_id_.erase(picture_buffer_id); 405} 406 407void VideoDecodeDemoInstance::PictureReady(PP_Resource decoder, 408 const PP_Picture_Dev& picture) { 409 if (first_frame_delivered_ticks_ == -1) 410 assert((first_frame_delivered_ticks_ = core_if_->GetTimeTicks()) != -1); 411 if (is_painting_) { 412 pictures_pending_paint_.push_back(std::make_pair(decoder, picture)); 413 return; 414 } 415 DecoderClient* client = video_decoders_[decoder]; 416 assert(client); 417 const PictureBufferInfo& info = 418 client->GetPictureBufferInfoById(picture.picture_buffer_id); 419 assert(!is_painting_); 420 is_painting_ = true; 421 int x = 0; 422 int y = 0; 423 if (client != video_decoders_.begin()->second) { 424 x = plugin_size_.width() / kNumDecoders; 425 y = plugin_size_.height() / kNumDecoders; 426 } 427 428 if (info.texture_target == GL_TEXTURE_2D) { 429 Create2DProgramOnce(); 430 gles2_if_->UseProgram(context_->pp_resource(), shader_2d_.program); 431 gles2_if_->Uniform2f( 432 context_->pp_resource(), shader_2d_.texcoord_scale_location, 1.0, 1.0); 433 } else { 434 assert(info.texture_target == GL_TEXTURE_RECTANGLE_ARB); 435 CreateRectangleARBProgramOnce(); 436 gles2_if_->UseProgram( 437 context_->pp_resource(), shader_rectangle_arb_.program); 438 gles2_if_->Uniform2f(context_->pp_resource(), 439 shader_rectangle_arb_.texcoord_scale_location, 440 info.buffer.size.width, 441 info.buffer.size.height); 442 } 443 444 gles2_if_->Viewport(context_->pp_resource(), x, y, 445 plugin_size_.width() / kNumDecoders, 446 plugin_size_.height() / kNumDecoders); 447 gles2_if_->ActiveTexture(context_->pp_resource(), GL_TEXTURE0); 448 gles2_if_->BindTexture( 449 context_->pp_resource(), info.texture_target, info.buffer.texture_id); 450 gles2_if_->DrawArrays(context_->pp_resource(), GL_TRIANGLE_STRIP, 0, 4); 451 452 gles2_if_->UseProgram(context_->pp_resource(), 0); 453 454 pp::CompletionCallback cb = 455 callback_factory_.NewCallback( 456 &VideoDecodeDemoInstance::PaintFinished, decoder, info.buffer.id); 457 last_swap_request_ticks_ = core_if_->GetTimeTicks(); 458 assert(context_->SwapBuffers(cb) == PP_OK_COMPLETIONPENDING); 459} 460 461void VideoDecodeDemoInstance::NotifyError(PP_Resource decoder, 462 PP_VideoDecodeError_Dev error) { 463 LogError(this).s() << "Received error: " << error; 464 assert(false && "Unexpected error; see stderr for details"); 465} 466 467// This object is the global object representing this plugin library as long 468// as it is loaded. 469class VideoDecodeDemoModule : public pp::Module { 470 public: 471 VideoDecodeDemoModule() : pp::Module() {} 472 virtual ~VideoDecodeDemoModule() {} 473 474 virtual pp::Instance* CreateInstance(PP_Instance instance) { 475 return new VideoDecodeDemoInstance(instance, this); 476 } 477}; 478 479void VideoDecodeDemoInstance::InitGL() { 480 assert(plugin_size_.width() && plugin_size_.height()); 481 is_painting_ = false; 482 483 assert(!context_); 484 int32_t context_attributes[] = { 485 PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8, 486 PP_GRAPHICS3DATTRIB_BLUE_SIZE, 8, 487 PP_GRAPHICS3DATTRIB_GREEN_SIZE, 8, 488 PP_GRAPHICS3DATTRIB_RED_SIZE, 8, 489 PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 0, 490 PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 0, 491 PP_GRAPHICS3DATTRIB_SAMPLES, 0, 492 PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, 0, 493 PP_GRAPHICS3DATTRIB_WIDTH, plugin_size_.width(), 494 PP_GRAPHICS3DATTRIB_HEIGHT, plugin_size_.height(), 495 PP_GRAPHICS3DATTRIB_NONE, 496 }; 497 context_ = new pp::Graphics3D(this, context_attributes); 498 assert(!context_->is_null()); 499 assert(BindGraphics(*context_)); 500 501 // Clear color bit. 502 gles2_if_->ClearColor(context_->pp_resource(), 1, 0, 0, 1); 503 gles2_if_->Clear(context_->pp_resource(), GL_COLOR_BUFFER_BIT); 504 505 assertNoGLError(); 506 507 CreateGLObjects(); 508} 509 510void VideoDecodeDemoInstance::PaintFinished(int32_t result, PP_Resource decoder, 511 int picture_buffer_id) { 512 assert(result == PP_OK); 513 swap_ticks_ += core_if_->GetTimeTicks() - last_swap_request_ticks_; 514 is_painting_ = false; 515 ++num_frames_rendered_; 516 if (num_frames_rendered_ % 50 == 0) { 517 double elapsed = core_if_->GetTimeTicks() - first_frame_delivered_ticks_; 518 double fps = (elapsed > 0) ? num_frames_rendered_ / elapsed : 1000; 519 double ms_per_swap = (swap_ticks_ * 1e3) / num_frames_rendered_; 520 LogError(this).s() << "Rendered frames: " << num_frames_rendered_ 521 << ", fps: " << fps << ", with average ms/swap of: " 522 << ms_per_swap; 523 } 524 DecoderClient* client = video_decoders_[decoder]; 525 if (client && client->decoder()) 526 client->decoder()->ReusePictureBuffer(picture_buffer_id); 527 if (!pictures_pending_paint_.empty()) { 528 std::pair<PP_Resource, PP_Picture_Dev> decoder_picture = 529 pictures_pending_paint_.front(); 530 pictures_pending_paint_.pop_front(); 531 PictureReady(decoder_picture.first, decoder_picture.second); 532 } 533} 534 535GLuint VideoDecodeDemoInstance::CreateTexture(int32_t width, 536 int32_t height, 537 GLenum texture_target) { 538 GLuint texture_id; 539 gles2_if_->GenTextures(context_->pp_resource(), 1, &texture_id); 540 assertNoGLError(); 541 // Assign parameters. 542 gles2_if_->ActiveTexture(context_->pp_resource(), GL_TEXTURE0); 543 gles2_if_->BindTexture(context_->pp_resource(), texture_target, texture_id); 544 gles2_if_->TexParameteri( 545 context_->pp_resource(), texture_target, GL_TEXTURE_MIN_FILTER, 546 GL_NEAREST); 547 gles2_if_->TexParameteri( 548 context_->pp_resource(), texture_target, GL_TEXTURE_MAG_FILTER, 549 GL_NEAREST); 550 gles2_if_->TexParameterf( 551 context_->pp_resource(), texture_target, GL_TEXTURE_WRAP_S, 552 GL_CLAMP_TO_EDGE); 553 gles2_if_->TexParameterf( 554 context_->pp_resource(), texture_target, GL_TEXTURE_WRAP_T, 555 GL_CLAMP_TO_EDGE); 556 557 if (texture_target == GL_TEXTURE_2D) { 558 gles2_if_->TexImage2D( 559 context_->pp_resource(), texture_target, 0, GL_RGBA, width, height, 0, 560 GL_RGBA, GL_UNSIGNED_BYTE, NULL); 561 } 562 assertNoGLError(); 563 return texture_id; 564} 565 566void VideoDecodeDemoInstance::DeleteTexture(GLuint id) { 567 gles2_if_->DeleteTextures(context_->pp_resource(), 1, &id); 568} 569 570void VideoDecodeDemoInstance::CreateGLObjects() { 571 // Assign vertex positions and texture coordinates to buffers for use in 572 // shader program. 573 static const float kVertices[] = { 574 -1, 1, -1, -1, 1, 1, 1, -1, // Position coordinates. 575 0, 1, 0, 0, 1, 1, 1, 0, // Texture coordinates. 576 }; 577 578 GLuint buffer; 579 gles2_if_->GenBuffers(context_->pp_resource(), 1, &buffer); 580 gles2_if_->BindBuffer(context_->pp_resource(), GL_ARRAY_BUFFER, buffer); 581 582 gles2_if_->BufferData(context_->pp_resource(), GL_ARRAY_BUFFER, 583 sizeof(kVertices), kVertices, GL_STATIC_DRAW); 584 assertNoGLError(); 585} 586 587static const char kVertexShader[] = 588 "varying vec2 v_texCoord; \n" 589 "attribute vec4 a_position; \n" 590 "attribute vec2 a_texCoord; \n" 591 "uniform vec2 v_scale; \n" 592 "void main() \n" 593 "{ \n" 594 " v_texCoord = v_scale * a_texCoord; \n" 595 " gl_Position = a_position; \n" 596 "}"; 597 598void VideoDecodeDemoInstance::Create2DProgramOnce() { 599 if (shader_2d_.program) 600 return; 601 static const char kFragmentShader2D[] = 602 "precision mediump float; \n" 603 "varying vec2 v_texCoord; \n" 604 "uniform sampler2D s_texture; \n" 605 "void main() \n" 606 "{" 607 " gl_FragColor = texture2D(s_texture, v_texCoord); \n" 608 "}"; 609 shader_2d_ = CreateProgram(kVertexShader, kFragmentShader2D); 610 assertNoGLError(); 611} 612 613void VideoDecodeDemoInstance::CreateRectangleARBProgramOnce() { 614 if (shader_rectangle_arb_.program) 615 return; 616 static const char kFragmentShaderRectangle[] = 617 "#extension GL_ARB_texture_rectangle : require\n" 618 "precision mediump float; \n" 619 "varying vec2 v_texCoord; \n" 620 "uniform sampler2DRect s_texture; \n" 621 "void main() \n" 622 "{" 623 " gl_FragColor = texture2DRect(s_texture, v_texCoord).rgba; \n" 624 "}"; 625 shader_rectangle_arb_ = 626 CreateProgram(kVertexShader, kFragmentShaderRectangle); 627} 628 629Shader VideoDecodeDemoInstance::CreateProgram(const char* vertex_shader, 630 const char* fragment_shader) { 631 Shader shader; 632 633 // Create shader program. 634 shader.program = gles2_if_->CreateProgram(context_->pp_resource()); 635 CreateShader(shader.program, GL_VERTEX_SHADER, vertex_shader, 636 strlen(vertex_shader)); 637 CreateShader(shader.program, GL_FRAGMENT_SHADER, fragment_shader, 638 strlen(fragment_shader)); 639 gles2_if_->LinkProgram(context_->pp_resource(), shader.program); 640 gles2_if_->UseProgram(context_->pp_resource(), shader.program); 641 gles2_if_->Uniform1i( 642 context_->pp_resource(), 643 gles2_if_->GetUniformLocation( 644 context_->pp_resource(), shader.program, "s_texture"), 0); 645 assertNoGLError(); 646 647 shader.texcoord_scale_location = gles2_if_->GetUniformLocation( 648 context_->pp_resource(), shader.program, "v_scale"); 649 650 GLint pos_location = gles2_if_->GetAttribLocation( 651 context_->pp_resource(), shader.program, "a_position"); 652 GLint tc_location = gles2_if_->GetAttribLocation( 653 context_->pp_resource(), shader.program, "a_texCoord"); 654 assertNoGLError(); 655 656 gles2_if_->EnableVertexAttribArray(context_->pp_resource(), pos_location); 657 gles2_if_->VertexAttribPointer(context_->pp_resource(), pos_location, 2, 658 GL_FLOAT, GL_FALSE, 0, 0); 659 gles2_if_->EnableVertexAttribArray(context_->pp_resource(), tc_location); 660 gles2_if_->VertexAttribPointer( 661 context_->pp_resource(), tc_location, 2, GL_FLOAT, GL_FALSE, 0, 662 static_cast<float*>(0) + 8); // Skip position coordinates. 663 664 gles2_if_->UseProgram(context_->pp_resource(), 0); 665 assertNoGLError(); 666 return shader; 667} 668 669void VideoDecodeDemoInstance::CreateShader( 670 GLuint program, GLenum type, const char* source, int size) { 671 GLuint shader = gles2_if_->CreateShader(context_->pp_resource(), type); 672 gles2_if_->ShaderSource(context_->pp_resource(), shader, 1, &source, &size); 673 gles2_if_->CompileShader(context_->pp_resource(), shader); 674 gles2_if_->AttachShader(context_->pp_resource(), program, shader); 675 gles2_if_->DeleteShader(context_->pp_resource(), shader); 676} 677} // anonymous namespace 678 679namespace pp { 680// Factory function for your specialization of the Module object. 681Module* CreateModule() { 682 return new VideoDecodeDemoModule(); 683} 684} // namespace pp 685