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