| Index: native_client_sdk/src/examples/api/video_decode/video_decode.cc
|
| diff --git a/native_client_sdk/src/examples/api/video_decode/video_decode.cc b/native_client_sdk/src/examples/api/video_decode/video_decode.cc
|
| index 7b1333f9f054cfa2a24e5a5553cef41aa489119e..ad667f2d1a49b1c81443350e68ea96bbdcee2ce9 100644
|
| --- a/native_client_sdk/src/examples/api/video_decode/video_decode.cc
|
| +++ b/native_client_sdk/src/examples/api/video_decode/video_decode.cc
|
| @@ -29,7 +29,6 @@
|
| #define USE_VP8_TESTDATA_INSTEAD_OF_H264
|
| #include "testdata.h"
|
|
|
| -
|
| // Use assert as a poor-man's CHECK, even in non-debug mode.
|
| // Since <assert.h> redefines assert on every inclusion (it doesn't use
|
| // include-guards), make sure this is the last file #include'd in this file.
|
| @@ -113,6 +112,7 @@ class MyInstance : public pp::Instance, public pp::Graphics3DClient {
|
| void CreateGLObjects();
|
| void Create2DProgramOnce();
|
| void CreateRectangleARBProgramOnce();
|
| + void CreateExternalOESProgramOnce();
|
| Shader CreateProgram(const char* vertex_shader, const char* fragment_shader);
|
| void CreateShader(GLuint program, GLenum type, const char* source, int size);
|
| void PaintNextPicture();
|
| @@ -145,6 +145,8 @@ class MyInstance : public pp::Instance, public pp::Graphics3DClient {
|
| Shader shader_2d_;
|
| // Shader program to draw GL_TEXTURE_RECTANGLE_ARB target.
|
| Shader shader_rectangle_arb_;
|
| + // Shader program to draw GL_TEXTURE_EXTERNAL_OES target.
|
| + Shader shader_external_oes_;
|
| };
|
|
|
| class Decoder {
|
| @@ -159,6 +161,10 @@ class Decoder {
|
| void Reset();
|
| void RecyclePicture(const PP_VideoPicture& picture);
|
|
|
| + PP_TimeTicks GetAverageLatency() {
|
| + return num_pictures_ ? total_latency_ / num_pictures_ : 0;
|
| + }
|
| +
|
| private:
|
| void InitializeDone(int32_t result);
|
| void Start();
|
| @@ -178,6 +184,12 @@ class Decoder {
|
| int next_picture_id_;
|
| bool flushing_;
|
| bool resetting_;
|
| +
|
| + const PPB_Core* core_if_;
|
| + static const int kMaxDecodeDelay = 128;
|
| + PP_TimeTicks decode_time_[kMaxDecodeDelay];
|
| + PP_TimeTicks total_latency_;
|
| + int num_pictures_;
|
| };
|
|
|
| #if defined USE_VP8_TESTDATA_INSTEAD_OF_H264
|
| @@ -227,7 +239,12 @@ Decoder::Decoder(MyInstance* instance,
|
| encoded_data_next_pos_to_decode_(0),
|
| next_picture_id_(0),
|
| flushing_(false),
|
| - resetting_(false) {
|
| + resetting_(false),
|
| + total_latency_(0.0),
|
| + num_pictures_(0) {
|
| + core_if_ = static_cast<const PPB_Core*>(
|
| + pp::Module::Get()->GetBrowserInterface(PPB_CORE_INTERFACE));
|
| +
|
| #if defined USE_VP8_TESTDATA_INSTEAD_OF_H264
|
| const PP_VideoProfile kBitstreamProfile = PP_VIDEOPROFILE_VP8MAIN;
|
| #else
|
| @@ -295,6 +312,7 @@ void Decoder::DecodeNextFrame() {
|
| // Decode the frame. On completion, DecodeDone will call DecodeNextFrame
|
| // to implement a decode loop.
|
| uint32_t size = static_cast<uint32_t>(end_pos - start_pos);
|
| + decode_time_[next_picture_id_ % kMaxDecodeDelay] = core_if_->GetTimeTicks();
|
| decoder_->Decode(next_picture_id_++,
|
| size,
|
| kData + start_pos,
|
| @@ -318,6 +336,12 @@ void Decoder::PictureReady(int32_t result, PP_VideoPicture picture) {
|
| if (result == PP_ERROR_ABORTED)
|
| return;
|
| assert(result == PP_OK);
|
| +
|
| + num_pictures_++;
|
| + PP_TimeTicks latency = core_if_->GetTimeTicks() -
|
| + decode_time_[picture.decode_id % kMaxDecodeDelay];
|
| + total_latency_ += latency;
|
| +
|
| decoder_->GetPicture(
|
| callback_factory_.NewCallbackWithOutput(&Decoder::PictureReady));
|
| instance_->PaintPicture(this, picture);
|
| @@ -349,12 +373,13 @@ MyInstance::MyInstance(PP_Instance instance, pp::Module* module)
|
| swap_ticks_(0),
|
| callback_factory_(this),
|
| context_(NULL) {
|
| - assert((console_if_ = static_cast<const PPB_Console*>(
|
| - module->GetBrowserInterface(PPB_CONSOLE_INTERFACE))));
|
| - assert((core_if_ = static_cast<const PPB_Core*>(
|
| - module->GetBrowserInterface(PPB_CORE_INTERFACE))));
|
| - assert((gles2_if_ = static_cast<const PPB_OpenGLES2*>(
|
| - module->GetBrowserInterface(PPB_OPENGLES2_INTERFACE))));
|
| + console_if_ = static_cast<const PPB_Console*>(
|
| + pp::Module::Get()->GetBrowserInterface(PPB_CONSOLE_INTERFACE));
|
| + core_if_ = static_cast<const PPB_Core*>(
|
| + pp::Module::Get()->GetBrowserInterface(PPB_CORE_INTERFACE));
|
| + gles2_if_ = static_cast<const PPB_OpenGLES2*>(
|
| + pp::Module::Get()->GetBrowserInterface(PPB_OPENGLES2_INTERFACE));
|
| +
|
| RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE);
|
| }
|
|
|
| @@ -367,6 +392,8 @@ MyInstance::~MyInstance() {
|
| gles2_if_->DeleteProgram(graphics_3d, shader_2d_.program);
|
| if (shader_rectangle_arb_.program)
|
| gles2_if_->DeleteProgram(graphics_3d, shader_rectangle_arb_.program);
|
| + if (shader_external_oes_.program)
|
| + gles2_if_->DeleteProgram(graphics_3d, shader_external_oes_.program);
|
|
|
| for (DecoderList::iterator it = video_decoders_.begin();
|
| it != video_decoders_.end();
|
| @@ -455,14 +482,19 @@ void MyInstance::PaintNextPicture() {
|
| gles2_if_->UseProgram(graphics_3d, shader_2d_.program);
|
| gles2_if_->Uniform2f(
|
| graphics_3d, shader_2d_.texcoord_scale_location, 1.0, 1.0);
|
| - } else {
|
| - assert(picture.texture_target == GL_TEXTURE_RECTANGLE_ARB);
|
| + } else if (picture.texture_target == GL_TEXTURE_RECTANGLE_ARB) {
|
| CreateRectangleARBProgramOnce();
|
| gles2_if_->UseProgram(graphics_3d, shader_rectangle_arb_.program);
|
| gles2_if_->Uniform2f(graphics_3d,
|
| shader_rectangle_arb_.texcoord_scale_location,
|
| picture.texture_size.width,
|
| picture.texture_size.height);
|
| + } else {
|
| + assert(picture.texture_target == GL_TEXTURE_EXTERNAL_OES);
|
| + CreateExternalOESProgramOnce();
|
| + gles2_if_->UseProgram(graphics_3d, shader_external_oes_.program);
|
| + gles2_if_->Uniform2f(
|
| + graphics_3d, shader_external_oes_.texcoord_scale_location, 1.0, 1.0);
|
| }
|
|
|
| gles2_if_->Viewport(graphics_3d, x, y, half_width, half_height);
|
| @@ -487,9 +519,18 @@ void MyInstance::PaintFinished(int32_t result) {
|
| double elapsed = core_if_->GetTimeTicks() - first_frame_delivered_ticks_;
|
| double fps = (elapsed > 0) ? num_frames_rendered_ / elapsed : 1000;
|
| double ms_per_swap = (swap_ticks_ * 1e3) / num_frames_rendered_;
|
| + double secs_average_latency = 0;
|
| + for (DecoderList::iterator it = video_decoders_.begin();
|
| + it != video_decoders_.end();
|
| + ++it)
|
| + secs_average_latency += (*it)->GetAverageLatency();
|
| + secs_average_latency /= video_decoders_.size();
|
| + double ms_average_latency = 1000 * secs_average_latency;
|
| LogError(this).s() << "Rendered frames: " << num_frames_rendered_
|
| << ", fps: " << fps
|
| - << ", with average ms/swap of: " << ms_per_swap;
|
| + << ", with average ms/swap of: " << ms_per_swap
|
| + << ", with average latency (ms) of: "
|
| + << ms_average_latency;
|
| }
|
|
|
| // If the decoders were reset, this will be empty.
|
| @@ -542,8 +583,8 @@ void MyInstance::CreateGLObjects() {
|
| // Assign vertex positions and texture coordinates to buffers for use in
|
| // shader program.
|
| static const float kVertices[] = {
|
| - -1, 1, -1, -1, 1, 1, 1, -1, // Position coordinates.
|
| - 0, 1, 0, 0, 1, 1, 1, 0, // Texture coordinates.
|
| + -1, -1, -1, 1, 1, -1, 1, 1, // Position coordinates.
|
| + 0, 1, 0, 0, 1, 1, 1, 0, // Texture coordinates.
|
| };
|
|
|
| GLuint buffer;
|
| @@ -598,6 +639,23 @@ void MyInstance::CreateRectangleARBProgramOnce() {
|
| "}";
|
| shader_rectangle_arb_ =
|
| CreateProgram(kVertexShader, kFragmentShaderRectangle);
|
| + assertNoGLError();
|
| +}
|
| +
|
| +void MyInstance::CreateExternalOESProgramOnce() {
|
| + if (shader_external_oes_.program)
|
| + return;
|
| + static const char kFragmentShaderExternal[] =
|
| + "#extension GL_OES_EGL_image_external : require\n"
|
| + "precision mediump float; \n"
|
| + "varying vec2 v_texCoord; \n"
|
| + "uniform samplerExternalOES s_texture; \n"
|
| + "void main() \n"
|
| + "{"
|
| + " gl_FragColor = texture2D(s_texture, v_texCoord); \n"
|
| + "}";
|
| + shader_external_oes_ = CreateProgram(kVertexShader, kFragmentShaderExternal);
|
| + assertNoGLError();
|
| }
|
|
|
| Shader MyInstance::CreateProgram(const char* vertex_shader,
|
|
|