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.
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.
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()));
43 struct PictureBufferInfo
{
44 PP_PictureBuffer_Dev buffer
;
45 GLenum texture_target
;
49 Shader() : program(0),
50 texcoord_scale_location(0) {}
53 GLint texcoord_scale_location
;
56 class VideoDecodeDemoInstance
: public pp::Instance
,
57 public pp::Graphics3DClient
,
58 public pp::VideoDecoderClient_Dev
{
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(
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
);
88 enum { kNumConcurrentDecodes
= 7,
89 kNumDecoders
= 2 }; // Baked into viewport rendering.
91 // A single decoder's client interface.
94 DecoderClient(VideoDecodeDemoInstance
* gles2
,
95 pp::VideoDecoder_Dev
* decoder
);
98 void DecodeNextNALUs();
100 // Per-decoder implementation of part of pp::VideoDecoderClient_Dev.
101 void ProvidePictureBuffers(
102 uint32_t req_num_of_bufs
,
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_
; }
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.
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;
153 LogError(VideoDecodeDemoInstance
* demo
) : demo_(demo
) {}
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_
; }
165 VideoDecodeDemoInstance
* demo_
; // Unowned.
166 std::ostringstream stream_
;
169 pp::Size plugin_size_
;
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_
;
181 const PPB_Console
* console_if_
;
182 const PPB_Core
* core_if_
;
183 const PPB_OpenGLES2
* gles2_if_
;
186 pp::Graphics3D
* context_
;
187 typedef std::map
<int, DecoderClient
*> Decoders
;
188 Decoders video_decoders_
;
190 // Shader program to draw GL_TEXTURE_2D target.
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() {
207 for (BitstreamBufferMap::iterator it
= bitstream_buffers_by_id_
.begin();
208 it
!= bitstream_buffers_by_id_
.end(); ++it
) {
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
,
222 : pp::Instance(instance
), pp::Graphics3DClient(this),
223 pp::VideoDecoderClient_Dev(this),
225 num_frames_rendered_(0),
226 first_frame_delivered_ticks_(-1),
228 callback_factory_(this),
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
))));
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
);
246 for (Decoders::iterator it
= video_decoders_
.begin();
247 it
!= video_decoders_
.end(); ++it
) {
250 video_decoders_
.clear();
254 void VideoDecodeDemoInstance::DidChangeView(
255 const pp::Rect
& position
, const pp::Rect
& clip_ignored
) {
256 if (position
.width() == 0 || position
.height() == 0)
258 if (plugin_size_
.width()) {
259 assert(position
.size() == plugin_size_
);
262 plugin_size_
= position
.size();
264 // Initialize graphics.
266 InitializeDecoders();
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();
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());
289 bitstream_buffers_by_id_
.erase(it
);
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
297 assert(bitstream_ids_at_decoder_
.empty());
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;
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
;
313 while (*end_pos
+ 3 < kDataLen
&&
314 !LookingAtNAL(kData
, *end_pos
)) {
317 if (*end_pos
+ 3 >= kDataLen
) {
323 void VideoDecodeDemoInstance::DecoderClient::DecodeNextNALUs() {
324 while (encoded_data_next_pos_to_decode_
<= kDataLen
&&
325 bitstream_ids_at_decoder_
.size() < kNumConcurrentDecodes
) {
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
);
338 size_t start_pos
= encoded_data_next_pos_to_decode_
;
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
);
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
);
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
];
364 client
->ProvidePictureBuffers(req_num_of_bufs
, dimensions
, texture_target
);
367 void VideoDecodeDemoInstance::DecoderClient::ProvidePictureBuffers(
368 uint32_t req_num_of_bufs
,
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_
;
380 buffers
.push_back(info
.buffer
);
381 assert(picture_buffers_by_id_
.insert(std::make_pair(id
, info
)).second
);
383 decoder_
->AssignPictureBuffers(buffers
);
386 const PictureBufferInfo
&
387 VideoDecodeDemoInstance::DecoderClient::GetPictureBufferInfoById(
389 PictureBufferMap::iterator it
= picture_buffers_by_id_
.find(id
);
390 assert(it
!= picture_buffers_by_id_
.end());
394 void VideoDecodeDemoInstance::DismissPictureBuffer(PP_Resource decoder
,
395 int32_t picture_buffer_id
) {
396 DecoderClient
* client
= video_decoders_
[decoder
];
398 client
->DismissPictureBuffer(picture_buffer_id
);
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
);
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);
413 pictures_pending_paint_
.push_back(std::make_pair(decoder
, picture
));
416 DecoderClient
* client
= video_decoders_
[decoder
];
418 const PictureBufferInfo
& info
=
419 client
->GetPictureBufferInfoById(picture
.picture_buffer_id
);
420 assert(!is_painting_
);
424 if (client
!= video_decoders_
.begin()->second
) {
425 x
= plugin_size_
.width() / kNumDecoders
;
426 y
= plugin_size_
.height() / kNumDecoders
;
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);
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
);
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);
453 gles2_if_
->UseProgram(context_
->pp_resource(), 0);
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
);
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");
468 // This object is the global object representing this plugin library as long
470 class VideoDecodeDemoModule
: public pp::Module
{
472 VideoDecodeDemoModule() : pp::Module() {}
473 virtual ~VideoDecodeDemoModule() {}
475 virtual pp::Instance
* CreateInstance(PP_Instance instance
) {
476 return new VideoDecodeDemoInstance(instance
, this);
480 void VideoDecodeDemoInstance::InitGL() {
481 assert(plugin_size_
.width() && plugin_size_
.height());
482 is_painting_
= false;
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
,
498 context_
= new pp::Graphics3D(this, context_attributes
);
499 assert(!context_
->is_null());
500 assert(BindGraphics(*context_
));
503 gles2_if_
->ClearColor(context_
->pp_resource(), 1, 0, 0, 1);
504 gles2_if_
->Clear(context_
->pp_resource(), GL_COLOR_BUFFER_BIT
);
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: "
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
);
536 GLuint
VideoDecodeDemoInstance::CreateTexture(int32_t width
,
538 GLenum texture_target
) {
540 gles2_if_
->GenTextures(context_
->pp_resource(), 1, &texture_id
);
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
,
548 gles2_if_
->TexParameteri(
549 context_
->pp_resource(), texture_target
, GL_TEXTURE_MAG_FILTER
,
551 gles2_if_
->TexParameterf(
552 context_
->pp_resource(), texture_target
, GL_TEXTURE_WRAP_S
,
554 gles2_if_
->TexParameterf(
555 context_
->pp_resource(), texture_target
, GL_TEXTURE_WRAP_T
,
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
);
567 void VideoDecodeDemoInstance::DeleteTexture(GLuint id
) {
568 gles2_if_
->DeleteTextures(context_
->pp_resource(), 1, &id
);
571 void VideoDecodeDemoInstance::CreateGLObjects() {
572 // Assign vertex positions and texture coordinates to buffers for use in
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.
580 gles2_if_
->GenBuffers(context_
->pp_resource(), 1, &buffer
);
581 gles2_if_
->BindBuffer(context_
->pp_resource(), GL_ARRAY_BUFFER
, buffer
);
583 gles2_if_
->BufferData(context_
->pp_resource(), GL_ARRAY_BUFFER
,
584 sizeof(kVertices
), kVertices
, GL_STATIC_DRAW
);
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"
595 " v_texCoord = v_scale * a_texCoord; \n"
596 " gl_Position = a_position; \n"
599 void VideoDecodeDemoInstance::Create2DProgramOnce() {
600 if (shader_2d_
.program
)
602 static const char kFragmentShader2D
[] =
603 "precision mediump float; \n"
604 "varying vec2 v_texCoord; \n"
605 "uniform sampler2D s_texture; \n"
608 " gl_FragColor = texture2D(s_texture, v_texCoord); \n"
610 shader_2d_
= CreateProgram(kVertexShader
, kFragmentShader2D
);
614 void VideoDecodeDemoInstance::CreateRectangleARBProgramOnce() {
615 if (shader_rectangle_arb_
.program
)
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"
624 " gl_FragColor = texture2DRect(s_texture, v_texCoord).rgba; \n"
626 shader_rectangle_arb_
=
627 CreateProgram(kVertexShader
, kFragmentShaderRectangle
);
630 Shader
VideoDecodeDemoInstance::CreateProgram(const char* vertex_shader
,
631 const char* fragment_shader
) {
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);
648 shader
.texcoord_scale_location
= gles2_if_
->GetUniformLocation(
649 context_
->pp_resource(), shader
.program
, "v_scale");
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");
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.
665 gles2_if_
->UseProgram(context_
->pp_resource(), 0);
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
);
678 } // anonymous namespace
681 // Factory function for your specialization of the Module object.
682 Module
* CreateModule() {
683 return new VideoDecodeDemoModule();