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),
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
))),
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
) {
253 video_decoders_
.clear();
257 void VideoDecodeDemoInstance::DidChangeView(
258 const pp::Rect
& position
, const pp::Rect
& clip_ignored
) {
259 if (position
.width() == 0 || position
.height() == 0)
261 if (plugin_size_
.width()) {
262 assert(position
.size() == plugin_size_
);
265 plugin_size_
= position
.size();
267 // Initialize graphics.
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());
292 bitstream_buffers_by_id_
.erase(it
);
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
300 assert(bitstream_ids_at_decoder_
.empty());
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
;
316 while (*end_pos
+ 3 < kDataLen
&&
317 !LookingAtNAL(kData
, *end_pos
)) {
320 if (*end_pos
+ 3 >= kDataLen
) {
326 void VideoDecodeDemoInstance::DecoderClient::DecodeNextNALUs() {
327 while (encoded_data_next_pos_to_decode_
<= kDataLen
&&
328 bitstream_ids_at_decoder_
.size() < kNumConcurrentDecodes
) {
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
);
341 size_t start_pos
= encoded_data_next_pos_to_decode_
;
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
);
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
);
361 void 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
];
367 client
->ProvidePictureBuffers(req_num_of_bufs
, dimensions
, texture_target
);
370 void VideoDecodeDemoInstance::DecoderClient::ProvidePictureBuffers(
371 uint32_t req_num_of_bufs
,
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_
;
383 buffers
.push_back(info
.buffer
);
384 assert(picture_buffers_by_id_
.insert(std::make_pair(id
, info
)).second
);
386 decoder_
->AssignPictureBuffers(buffers
);
389 const PictureBufferInfo
&
390 VideoDecodeDemoInstance::DecoderClient::GetPictureBufferInfoById(
392 PictureBufferMap::iterator it
= picture_buffers_by_id_
.find(id
);
393 assert(it
!= picture_buffers_by_id_
.end());
397 void VideoDecodeDemoInstance::DismissPictureBuffer(PP_Resource decoder
,
398 int32_t picture_buffer_id
) {
399 DecoderClient
* client
= video_decoders_
[decoder
];
401 client
->DismissPictureBuffer(picture_buffer_id
);
404 void 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
);
411 void 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);
416 pictures_pending_paint_
.push_back(std::make_pair(decoder
, picture
));
419 DecoderClient
* client
= video_decoders_
[decoder
];
421 const PictureBufferInfo
& info
=
422 client
->GetPictureBufferInfoById(picture
.picture_buffer_id
);
423 assert(!is_painting_
);
427 if (client
!= video_decoders_
.begin()->second
) {
428 x
= plugin_size_
.width() / kNumDecoders
;
429 y
= plugin_size_
.height() / kNumDecoders
;
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);
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
);
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);
456 gles2_if_
->UseProgram(context_
->pp_resource(), 0);
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
);
465 void 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");
471 // This object is the global object representing this plugin library as long
473 class VideoDecodeDemoModule
: public pp::Module
{
475 VideoDecodeDemoModule() : pp::Module() {}
476 virtual ~VideoDecodeDemoModule() {}
478 virtual pp::Instance
* CreateInstance(PP_Instance instance
) {
479 return new VideoDecodeDemoInstance(instance
, this);
483 void VideoDecodeDemoInstance::InitGL() {
484 assert(plugin_size_
.width() && plugin_size_
.height());
485 is_painting_
= false;
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
,
501 context_
= new pp::Graphics3D(this, context_attributes
);
502 assert(!context_
->is_null());
503 assert(BindGraphics(*context_
));
506 gles2_if_
->ClearColor(context_
->pp_resource(), 1, 0, 0, 1);
507 gles2_if_
->Clear(context_
->pp_resource(), GL_COLOR_BUFFER_BIT
);
514 void 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: "
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
);
539 GLuint
VideoDecodeDemoInstance::CreateTexture(int32_t width
,
541 GLenum texture_target
) {
543 gles2_if_
->GenTextures(context_
->pp_resource(), 1, &texture_id
);
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
,
551 gles2_if_
->TexParameteri(
552 context_
->pp_resource(), texture_target
, GL_TEXTURE_MAG_FILTER
,
554 gles2_if_
->TexParameterf(
555 context_
->pp_resource(), texture_target
, GL_TEXTURE_WRAP_S
,
557 gles2_if_
->TexParameterf(
558 context_
->pp_resource(), texture_target
, GL_TEXTURE_WRAP_T
,
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
);
570 void VideoDecodeDemoInstance::DeleteTexture(GLuint id
) {
571 gles2_if_
->DeleteTextures(context_
->pp_resource(), 1, &id
);
574 void VideoDecodeDemoInstance::CreateGLObjects() {
575 // Assign vertex positions and texture coordinates to buffers for use in
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.
583 gles2_if_
->GenBuffers(context_
->pp_resource(), 1, &buffer
);
584 gles2_if_
->BindBuffer(context_
->pp_resource(), GL_ARRAY_BUFFER
, buffer
);
586 gles2_if_
->BufferData(context_
->pp_resource(), GL_ARRAY_BUFFER
,
587 sizeof(kVertices
), kVertices
, GL_STATIC_DRAW
);
591 static 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"
598 " v_texCoord = v_scale * a_texCoord; \n"
599 " gl_Position = a_position; \n"
602 void VideoDecodeDemoInstance::Create2DProgramOnce() {
603 if (shader_2d_
.program
)
605 static const char kFragmentShader2D
[] =
606 "precision mediump float; \n"
607 "varying vec2 v_texCoord; \n"
608 "uniform sampler2D s_texture; \n"
611 " gl_FragColor = texture2D(s_texture, v_texCoord); \n"
613 shader_2d_
= CreateProgram(kVertexShader
, kFragmentShader2D
);
617 void VideoDecodeDemoInstance::CreateRectangleARBProgramOnce() {
618 if (shader_rectangle_arb_
.program
)
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"
627 " gl_FragColor = texture2DRect(s_texture, v_texCoord).rgba; \n"
629 shader_rectangle_arb_
=
630 CreateProgram(kVertexShader
, kFragmentShaderRectangle
);
633 Shader
VideoDecodeDemoInstance::CreateProgram(const char* vertex_shader
,
634 const char* fragment_shader
) {
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);
651 shader
.texcoord_scale_location
= gles2_if_
->GetUniformLocation(
652 context_
->pp_resource(), shader
.program
, "v_scale");
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");
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.
668 gles2_if_
->UseProgram(context_
->pp_resource(), 0);
673 void 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
);
681 } // anonymous namespace
684 // Factory function for your specialization of the Module object.
685 Module
* CreateModule() {
686 return new VideoDecodeDemoModule();