Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / ppapi / examples / video_decode / video_decode_dev.cc
blob1cacb1b37e468cd6847e0e81b97eb1ef2ea7e25a
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.
5 #include <string.h>
7 #include <iostream>
8 #include <list>
9 #include <map>
10 #include <set>
11 #include <sstream>
12 #include <vector>
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"
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>
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()));
41 namespace {
43 struct PictureBufferInfo {
44 PP_PictureBuffer_Dev buffer;
45 GLenum texture_target;
48 struct Shader {
49 Shader() : program(0),
50 texcoord_scale_location(0) {}
52 GLuint program;
53 GLint texcoord_scale_location;
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();
63 // pp::Instance implementation (see PPP_Instance).
64 virtual void DidChangeView(const pp::Rect& position,
65 const pp::Rect& clip_ignored);
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");
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);
87 private:
88 enum { kNumConcurrentDecodes = 7,
89 kNumDecoders = 2 }; // Baked into viewport rendering.
91 // A single decoder's client interface.
92 class DecoderClient {
93 public:
94 DecoderClient(VideoDecodeDemoInstance* gles2,
95 pp::VideoDecoder_Dev* decoder);
96 ~DecoderClient();
98 void DecodeNextNALUs();
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);
107 const PictureBufferInfo& GetPictureBufferInfoById(int id);
108 pp::VideoDecoder_Dev* decoder() { return decoder_; }
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);
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_;
131 // Initialize Video Decoders.
132 void InitializeDecoders();
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);
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;
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_;
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_;
180 // Unowned pointers.
181 const PPB_Console* console_if_;
182 const PPB_Core* core_if_;
183 const PPB_OpenGLES2* gles2_if_;
185 // Owned data.
186 pp::Graphics3D* context_;
187 typedef std::map<int, DecoderClient*> Decoders;
188 Decoders video_decoders_;
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_;
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) {
203 VideoDecodeDemoInstance::DecoderClient::~DecoderClient() {
204 delete decoder_;
205 decoder_ = NULL;
207 for (BitstreamBufferMap::iterator it = bitstream_buffers_by_id_.begin();
208 it != bitstream_buffers_by_id_.end(); ++it) {
209 delete it->second;
211 bitstream_buffers_by_id_.clear();
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);
217 picture_buffers_by_id_.clear();
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 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_);
241 VideoDecodeDemoInstance::~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);
249 for (Decoders::iterator it = video_decoders_.begin();
250 it != video_decoders_.end(); ++it) {
251 delete it->second;
253 video_decoders_.clear();
254 delete context_;
257 void 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;
265 plugin_size_ = position.size();
267 // Initialize graphics.
268 InitGL();
269 InitializeDecoders();
272 void 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();
285 void 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();
296 void 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;
305 static 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;
311 void 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;
320 if (*end_pos + 3 >= kDataLen) {
321 *end_pos = kDataLen;
322 return;
326 void VideoDecodeDemoInstance::DecoderClient::DecodeNextNALUs() {
327 while (encoded_data_next_pos_to_decode_ <= kDataLen &&
328 bitstream_ids_at_decoder_.size() < kNumConcurrentDecodes) {
329 DecodeNextNALU();
333 void 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;
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(
345 gles2_, static_cast<uint32_t>(end_pos - start_pos));
346 PP_VideoBitstreamBuffer_Dev bitstream_buffer;
347 int id = ++next_bitstream_buffer_id_;
348 bitstream_buffer.id = id;
349 bitstream_buffer.size = static_cast<uint32_t>(end_pos - start_pos);
350 bitstream_buffer.data = buffer->pp_resource();
351 memcpy(buffer->data(), kData + start_pos, end_pos - start_pos);
352 assert(bitstream_buffers_by_id_.insert(std::make_pair(id, buffer)).second);
354 pp::CompletionCallback cb =
355 callback_factory_.NewCallback(
356 &VideoDecodeDemoInstance::DecoderClient::DecoderBitstreamDone, id);
357 assert(bitstream_ids_at_decoder_.insert(id).second);
358 encoded_data_next_pos_to_decode_ = end_pos;
359 decoder_->Decode(bitstream_buffer, cb);
362 void VideoDecodeDemoInstance::ProvidePictureBuffers(PP_Resource decoder,
363 uint32_t req_num_of_bufs,
364 const PP_Size& dimensions,
365 uint32_t texture_target) {
366 DecoderClient* client = video_decoders_[decoder];
367 assert(client);
368 client->ProvidePictureBuffers(req_num_of_bufs, dimensions, texture_target);
371 void VideoDecodeDemoInstance::DecoderClient::ProvidePictureBuffers(
372 uint32_t req_num_of_bufs,
373 PP_Size dimensions,
374 uint32_t texture_target) {
375 std::vector<PP_PictureBuffer_Dev> buffers;
376 for (uint32_t i = 0; i < req_num_of_bufs; ++i) {
377 PictureBufferInfo info;
378 info.buffer.size = dimensions;
379 info.texture_target = texture_target;
380 info.buffer.texture_id = gles2_->CreateTexture(
381 dimensions.width, dimensions.height, info.texture_target);
382 int id = ++next_picture_buffer_id_;
383 info.buffer.id = id;
384 buffers.push_back(info.buffer);
385 assert(picture_buffers_by_id_.insert(std::make_pair(id, info)).second);
387 decoder_->AssignPictureBuffers(buffers);
390 const PictureBufferInfo&
391 VideoDecodeDemoInstance::DecoderClient::GetPictureBufferInfoById(
392 int id) {
393 PictureBufferMap::iterator it = picture_buffers_by_id_.find(id);
394 assert(it != picture_buffers_by_id_.end());
395 return it->second;
398 void VideoDecodeDemoInstance::DismissPictureBuffer(PP_Resource decoder,
399 int32_t picture_buffer_id) {
400 DecoderClient* client = video_decoders_[decoder];
401 assert(client);
402 client->DismissPictureBuffer(picture_buffer_id);
405 void VideoDecodeDemoInstance::DecoderClient::DismissPictureBuffer(
406 int32_t picture_buffer_id) {
407 gles2_->DeleteTexture(GetPictureBufferInfoById(
408 picture_buffer_id).buffer.texture_id);
409 picture_buffers_by_id_.erase(picture_buffer_id);
412 void VideoDecodeDemoInstance::PictureReady(PP_Resource decoder,
413 const PP_Picture_Dev& picture) {
414 if (first_frame_delivered_ticks_ == -1)
415 assert((first_frame_delivered_ticks_ = core_if_->GetTimeTicks()) != -1);
416 if (is_painting_) {
417 pictures_pending_paint_.push_back(std::make_pair(decoder, picture));
418 return;
420 DecoderClient* client = video_decoders_[decoder];
421 assert(client);
422 const PictureBufferInfo& info =
423 client->GetPictureBufferInfoById(picture.picture_buffer_id);
424 assert(!is_painting_);
425 is_painting_ = true;
426 int x = 0;
427 int y = 0;
428 if (client != video_decoders_.begin()->second) {
429 x = plugin_size_.width() / kNumDecoders;
430 y = plugin_size_.height() / kNumDecoders;
433 if (info.texture_target == GL_TEXTURE_2D) {
434 Create2DProgramOnce();
435 gles2_if_->UseProgram(context_->pp_resource(), shader_2d_.program);
436 gles2_if_->Uniform2f(
437 context_->pp_resource(), shader_2d_.texcoord_scale_location, 1.0, 1.0);
438 } else {
439 assert(info.texture_target == GL_TEXTURE_RECTANGLE_ARB);
440 CreateRectangleARBProgramOnce();
441 gles2_if_->UseProgram(
442 context_->pp_resource(), shader_rectangle_arb_.program);
443 gles2_if_->Uniform2f(context_->pp_resource(),
444 shader_rectangle_arb_.texcoord_scale_location,
445 static_cast<GLfloat>(info.buffer.size.width),
446 static_cast<GLfloat>(info.buffer.size.height));
449 gles2_if_->Viewport(context_->pp_resource(), x, y,
450 plugin_size_.width() / kNumDecoders,
451 plugin_size_.height() / kNumDecoders);
452 gles2_if_->ActiveTexture(context_->pp_resource(), GL_TEXTURE0);
453 gles2_if_->BindTexture(
454 context_->pp_resource(), info.texture_target, info.buffer.texture_id);
455 gles2_if_->DrawArrays(context_->pp_resource(), GL_TRIANGLE_STRIP, 0, 4);
457 gles2_if_->UseProgram(context_->pp_resource(), 0);
459 pp::CompletionCallback cb =
460 callback_factory_.NewCallback(
461 &VideoDecodeDemoInstance::PaintFinished, decoder, info.buffer.id);
462 last_swap_request_ticks_ = core_if_->GetTimeTicks();
463 assert(context_->SwapBuffers(cb) == PP_OK_COMPLETIONPENDING);
466 void VideoDecodeDemoInstance::NotifyError(PP_Resource decoder,
467 PP_VideoDecodeError_Dev error) {
468 LogError(this).s() << "Received error: " << error;
469 assert(false && "Unexpected error; see stderr for details");
472 // This object is the global object representing this plugin library as long
473 // as it is loaded.
474 class VideoDecodeDemoModule : public pp::Module {
475 public:
476 VideoDecodeDemoModule() : pp::Module() {}
477 virtual ~VideoDecodeDemoModule() {}
479 virtual pp::Instance* CreateInstance(PP_Instance instance) {
480 return new VideoDecodeDemoInstance(instance, this);
484 void VideoDecodeDemoInstance::InitGL() {
485 assert(plugin_size_.width() && plugin_size_.height());
486 is_painting_ = false;
488 assert(!context_);
489 int32_t context_attributes[] = {
490 PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8,
491 PP_GRAPHICS3DATTRIB_BLUE_SIZE, 8,
492 PP_GRAPHICS3DATTRIB_GREEN_SIZE, 8,
493 PP_GRAPHICS3DATTRIB_RED_SIZE, 8,
494 PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 0,
495 PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 0,
496 PP_GRAPHICS3DATTRIB_SAMPLES, 0,
497 PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, 0,
498 PP_GRAPHICS3DATTRIB_WIDTH, plugin_size_.width(),
499 PP_GRAPHICS3DATTRIB_HEIGHT, plugin_size_.height(),
500 PP_GRAPHICS3DATTRIB_NONE,
502 context_ = new pp::Graphics3D(this, context_attributes);
503 assert(!context_->is_null());
504 assert(BindGraphics(*context_));
506 // Clear color bit.
507 gles2_if_->ClearColor(context_->pp_resource(), 1, 0, 0, 1);
508 gles2_if_->Clear(context_->pp_resource(), GL_COLOR_BUFFER_BIT);
510 assertNoGLError();
512 CreateGLObjects();
515 void VideoDecodeDemoInstance::PaintFinished(int32_t result, PP_Resource decoder,
516 int picture_buffer_id) {
517 assert(result == PP_OK);
518 swap_ticks_ += core_if_->GetTimeTicks() - last_swap_request_ticks_;
519 is_painting_ = false;
520 ++num_frames_rendered_;
521 if (num_frames_rendered_ % 50 == 0) {
522 double elapsed = core_if_->GetTimeTicks() - first_frame_delivered_ticks_;
523 double fps = (elapsed > 0) ? num_frames_rendered_ / elapsed : 1000;
524 double ms_per_swap = (swap_ticks_ * 1e3) / num_frames_rendered_;
525 LogError(this).s() << "Rendered frames: " << num_frames_rendered_
526 << ", fps: " << fps << ", with average ms/swap of: "
527 << ms_per_swap;
529 DecoderClient* client = video_decoders_[decoder];
530 if (client && client->decoder())
531 client->decoder()->ReusePictureBuffer(picture_buffer_id);
532 if (!pictures_pending_paint_.empty()) {
533 std::pair<PP_Resource, PP_Picture_Dev> decoder_picture =
534 pictures_pending_paint_.front();
535 pictures_pending_paint_.pop_front();
536 PictureReady(decoder_picture.first, decoder_picture.second);
540 GLuint VideoDecodeDemoInstance::CreateTexture(int32_t width,
541 int32_t height,
542 GLenum texture_target) {
543 GLuint texture_id;
544 gles2_if_->GenTextures(context_->pp_resource(), 1, &texture_id);
545 assertNoGLError();
546 // Assign parameters.
547 gles2_if_->ActiveTexture(context_->pp_resource(), GL_TEXTURE0);
548 gles2_if_->BindTexture(context_->pp_resource(), texture_target, texture_id);
549 gles2_if_->TexParameteri(
550 context_->pp_resource(), texture_target, GL_TEXTURE_MIN_FILTER,
551 GL_NEAREST);
552 gles2_if_->TexParameteri(
553 context_->pp_resource(), texture_target, GL_TEXTURE_MAG_FILTER,
554 GL_NEAREST);
555 gles2_if_->TexParameterf(
556 context_->pp_resource(), texture_target, GL_TEXTURE_WRAP_S,
557 GL_CLAMP_TO_EDGE);
558 gles2_if_->TexParameterf(
559 context_->pp_resource(), texture_target, GL_TEXTURE_WRAP_T,
560 GL_CLAMP_TO_EDGE);
562 if (texture_target == GL_TEXTURE_2D) {
563 gles2_if_->TexImage2D(
564 context_->pp_resource(), texture_target, 0, GL_RGBA, width, height, 0,
565 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
567 assertNoGLError();
568 return texture_id;
571 void VideoDecodeDemoInstance::DeleteTexture(GLuint id) {
572 gles2_if_->DeleteTextures(context_->pp_resource(), 1, &id);
575 void VideoDecodeDemoInstance::CreateGLObjects() {
576 // Assign vertex positions and texture coordinates to buffers for use in
577 // shader program.
578 static const float kVertices[] = {
579 -1, 1, -1, -1, 1, 1, 1, -1, // Position coordinates.
580 0, 1, 0, 0, 1, 1, 1, 0, // Texture coordinates.
583 GLuint buffer;
584 gles2_if_->GenBuffers(context_->pp_resource(), 1, &buffer);
585 gles2_if_->BindBuffer(context_->pp_resource(), GL_ARRAY_BUFFER, buffer);
587 gles2_if_->BufferData(context_->pp_resource(), GL_ARRAY_BUFFER,
588 sizeof(kVertices), kVertices, GL_STATIC_DRAW);
589 assertNoGLError();
592 static const char kVertexShader[] =
593 "varying vec2 v_texCoord; \n"
594 "attribute vec4 a_position; \n"
595 "attribute vec2 a_texCoord; \n"
596 "uniform vec2 v_scale; \n"
597 "void main() \n"
598 "{ \n"
599 " v_texCoord = v_scale * a_texCoord; \n"
600 " gl_Position = a_position; \n"
601 "}";
603 void VideoDecodeDemoInstance::Create2DProgramOnce() {
604 if (shader_2d_.program)
605 return;
606 static const char kFragmentShader2D[] =
607 "precision mediump float; \n"
608 "varying vec2 v_texCoord; \n"
609 "uniform sampler2D s_texture; \n"
610 "void main() \n"
612 " gl_FragColor = texture2D(s_texture, v_texCoord); \n"
613 "}";
614 shader_2d_ = CreateProgram(kVertexShader, kFragmentShader2D);
615 assertNoGLError();
618 void VideoDecodeDemoInstance::CreateRectangleARBProgramOnce() {
619 if (shader_rectangle_arb_.program)
620 return;
621 static const char kFragmentShaderRectangle[] =
622 "#extension GL_ARB_texture_rectangle : require\n"
623 "precision mediump float; \n"
624 "varying vec2 v_texCoord; \n"
625 "uniform sampler2DRect s_texture; \n"
626 "void main() \n"
628 " gl_FragColor = texture2DRect(s_texture, v_texCoord).rgba; \n"
629 "}";
630 shader_rectangle_arb_ =
631 CreateProgram(kVertexShader, kFragmentShaderRectangle);
634 Shader VideoDecodeDemoInstance::CreateProgram(const char* vertex_shader,
635 const char* fragment_shader) {
636 Shader shader;
638 // Create shader program.
639 shader.program = gles2_if_->CreateProgram(context_->pp_resource());
640 CreateShader(shader.program, GL_VERTEX_SHADER, vertex_shader,
641 static_cast<int>(strlen(vertex_shader)));
642 CreateShader(shader.program, GL_FRAGMENT_SHADER, fragment_shader,
643 static_cast<int>(strlen(fragment_shader)));
644 gles2_if_->LinkProgram(context_->pp_resource(), shader.program);
645 gles2_if_->UseProgram(context_->pp_resource(), shader.program);
646 gles2_if_->Uniform1i(
647 context_->pp_resource(),
648 gles2_if_->GetUniformLocation(
649 context_->pp_resource(), shader.program, "s_texture"), 0);
650 assertNoGLError();
652 shader.texcoord_scale_location = gles2_if_->GetUniformLocation(
653 context_->pp_resource(), shader.program, "v_scale");
655 GLint pos_location = gles2_if_->GetAttribLocation(
656 context_->pp_resource(), shader.program, "a_position");
657 GLint tc_location = gles2_if_->GetAttribLocation(
658 context_->pp_resource(), shader.program, "a_texCoord");
659 assertNoGLError();
661 gles2_if_->EnableVertexAttribArray(context_->pp_resource(), pos_location);
662 gles2_if_->VertexAttribPointer(context_->pp_resource(), pos_location, 2,
663 GL_FLOAT, GL_FALSE, 0, 0);
664 gles2_if_->EnableVertexAttribArray(context_->pp_resource(), tc_location);
665 gles2_if_->VertexAttribPointer(
666 context_->pp_resource(), tc_location, 2, GL_FLOAT, GL_FALSE, 0,
667 static_cast<float*>(0) + 8); // Skip position coordinates.
669 gles2_if_->UseProgram(context_->pp_resource(), 0);
670 assertNoGLError();
671 return shader;
674 void VideoDecodeDemoInstance::CreateShader(
675 GLuint program, GLenum type, const char* source, int size) {
676 GLuint shader = gles2_if_->CreateShader(context_->pp_resource(), type);
677 gles2_if_->ShaderSource(context_->pp_resource(), shader, 1, &source, &size);
678 gles2_if_->CompileShader(context_->pp_resource(), shader);
679 gles2_if_->AttachShader(context_->pp_resource(), program, shader);
680 gles2_if_->DeleteShader(context_->pp_resource(), shader);
682 } // anonymous namespace
684 namespace pp {
685 // Factory function for your specialization of the Module object.
686 Module* CreateModule() {
687 return new VideoDecodeDemoModule();
689 } // namespace pp