Index: ppapi/examples/media_stream_video/media_stream_video.cc |
diff --git a/ppapi/examples/media_stream_video/media_stream_video.cc b/ppapi/examples/media_stream_video/media_stream_video.cc |
index 3635e0e8cd89b8d257bec28f016aa0630d80fd75..f46256bb461128db577ab7af90ae57956087cd8a 100644 |
--- a/ppapi/examples/media_stream_video/media_stream_video.cc |
+++ b/ppapi/examples/media_stream_video/media_stream_video.cc |
@@ -2,6 +2,8 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
+#include <vector> |
+ |
#include "ppapi/c/pp_errors.h" |
#include "ppapi/c/ppb_opengles2.h" |
#include "ppapi/cpp/completion_callback.h" |
@@ -15,6 +17,7 @@ |
#include "ppapi/cpp/var.h" |
#include "ppapi/cpp/video_frame.h" |
#include "ppapi/lib/gl/include/GLES2/gl2.h" |
+#include "ppapi/lib/gl/include/GLES2/gl2ext.h" |
#include "ppapi/utility/completion_callback_factory.h" |
// When compiling natively on Windows, PostMessage can be #define-d to |
@@ -54,32 +57,42 @@ class MediaStreamVideoDemoInstance : public pp::Instance, |
// pp::Graphics3DClient implementation. |
virtual void Graphics3DContextLost() { |
InitGL(); |
- CreateYUVTextures(); |
+ CreateTextures(); |
Render(); |
} |
private: |
+ void DrawYUV(); |
+ void DrawRGB(); |
void Render(); |
// GL-related functions. |
void InitGL(); |
- GLuint CreateTexture(int32_t width, int32_t height, int unit); |
+ GLuint CreateTexture(int32_t width, int32_t height, int unit, bool rgba); |
void CreateGLObjects(); |
void CreateShader(GLuint program, GLenum type, const char* source, int size); |
void PaintFinished(int32_t result); |
- void CreateYUVTextures(); |
+ void CreateTextures(); |
+ |
- // Callback that is invoked when new frames are recevied. |
+ // MediaStreamVideoTrack callbacks. |
+ void OnConfigure(int32_t result); |
void OnGetFrame(int32_t result, pp::VideoFrame frame); |
pp::Size position_size_; |
bool is_painting_; |
bool needs_paint_; |
+ bool is_bgra_; |
+ GLuint program_yuv_; |
+ GLuint program_rgb_; |
+ GLuint buffer_; |
GLuint texture_y_; |
GLuint texture_u_; |
GLuint texture_v_; |
+ GLuint texture_rgb_; |
pp::MediaStreamVideoTrack video_track_; |
pp::CompletionCallbackFactory<MediaStreamVideoDemoInstance> callback_factory_; |
+ std::vector<int32_t> attrib_list_; |
// Unowned pointers. |
const struct PPB_OpenGLES2* gles2_if_; |
@@ -96,9 +109,11 @@ MediaStreamVideoDemoInstance::MediaStreamVideoDemoInstance( |
pp::Graphics3DClient(this), |
is_painting_(false), |
needs_paint_(false), |
+ is_bgra_(false), |
texture_y_(0), |
texture_u_(0), |
texture_v_(0), |
+ texture_rgb_(0), |
callback_factory_(this), |
context_(NULL) { |
gles2_if_ = static_cast<const struct PPB_OpenGLES2*>( |
@@ -127,17 +142,45 @@ void MediaStreamVideoDemoInstance::DidChangeView( |
void MediaStreamVideoDemoInstance::HandleMessage(const pp::Var& var_message) { |
if (!var_message.is_dictionary()) |
return; |
- pp::VarDictionary var_dictionary_message(var_message); |
- pp::Var var_track = var_dictionary_message.Get("track"); |
- if (!var_track.is_resource()) |
- return; |
- |
- pp::Resource resource_track = pp::VarResource_Dev(var_track).AsResource(); |
- |
- video_track_ = pp::MediaStreamVideoTrack(resource_track); |
- video_track_.GetFrame(callback_factory_.NewCallbackWithOutput( |
- &MediaStreamVideoDemoInstance::OnGetFrame)); |
+ pp::VarDictionary var_dictionary_message(var_message); |
+ std::string command = var_dictionary_message.Get("command").AsString(); |
+ |
+ if (command == "init") { |
+ pp::Var var_track = var_dictionary_message.Get("track"); |
+ if (!var_track.is_resource()) |
+ return; |
+ pp::Resource resource_track = pp::VarResource_Dev(var_track).AsResource(); |
+ video_track_ = pp::MediaStreamVideoTrack(resource_track); |
+ const int32_t attrib_list[] = { |
+ PP_MEDIASTREAMVIDEOTRACK_ATTRIB_FORMAT, PP_VIDEOFRAME_FORMAT_I420, |
+ PP_MEDIASTREAMVIDEOTRACK_ATTRIB_NONE |
+ }; |
+ video_track_.Configure(attrib_list, callback_factory_.NewCallback( |
+ &MediaStreamVideoDemoInstance::OnConfigure)); |
+ } else if (command == "format") { |
+ std::string str_format = var_dictionary_message.Get("format").AsString(); |
+ PP_VideoFrame_Format format = PP_VIDEOFRAME_FORMAT_UNKNOWN; |
+ if (str_format == "YV12") { |
+ format = PP_VIDEOFRAME_FORMAT_YV12; |
+ } else if (str_format == "I420") { |
+ format = PP_VIDEOFRAME_FORMAT_I420; |
+ } else if (str_format == "BGRA") { |
+ format = PP_VIDEOFRAME_FORMAT_BGRA; |
+ } |
+ |
+ attrib_list_.clear(); |
+ attrib_list_.push_back(PP_MEDIASTREAMVIDEOTRACK_ATTRIB_FORMAT); |
+ attrib_list_.push_back(format); |
+ attrib_list_.push_back(PP_MEDIASTREAMVIDEOTRACK_ATTRIB_NONE); |
+ } else if (command == "size") { |
+ attrib_list_.clear(); |
+ attrib_list_.push_back(PP_MEDIASTREAMVIDEOTRACK_ATTRIB_WIDTH); |
+ attrib_list_.push_back(var_dictionary_message.Get("width").AsInt()); |
+ attrib_list_.push_back(PP_MEDIASTREAMVIDEOTRACK_ATTRIB_HEIGHT); |
+ attrib_list_.push_back(var_dictionary_message.Get("height").AsInt()); |
+ attrib_list_.push_back(PP_MEDIASTREAMVIDEOTRACK_ATTRIB_NONE); |
+ } |
} |
void MediaStreamVideoDemoInstance::InitGL() { |
@@ -173,12 +216,77 @@ void MediaStreamVideoDemoInstance::InitGL() { |
CreateGLObjects(); |
} |
+void MediaStreamVideoDemoInstance::DrawYUV() { |
+ PP_Resource context = context_->pp_resource(); |
+ static const float kColorMatrix[9] = { |
+ 1.1643828125f, 1.1643828125f, 1.1643828125f, |
+ 0.0f, -0.39176171875f, 2.017234375f, |
+ 1.59602734375f, -0.81296875f, 0.0f |
+ }; |
+ |
+ gles2_if_->UseProgram(context, program_yuv_); |
+ gles2_if_->Uniform1i(context, gles2_if_->GetUniformLocation( |
+ context, program_yuv_, "y_texture"), 0); |
+ gles2_if_->Uniform1i(context, gles2_if_->GetUniformLocation( |
+ context, program_yuv_, "u_texture"), 1); |
+ gles2_if_->Uniform1i(context, gles2_if_->GetUniformLocation( |
+ context, program_yuv_, "v_texture"), 2); |
+ gles2_if_->UniformMatrix3fv( |
+ context, |
+ gles2_if_->GetUniformLocation(context, program_yuv_, "color_matrix"), |
+ 1, GL_FALSE, kColorMatrix); |
+ AssertNoGLError(); |
+ |
+ GLint pos_location = gles2_if_->GetAttribLocation( |
+ context, program_yuv_, "a_position"); |
+ GLint tc_location = gles2_if_->GetAttribLocation( |
+ context, program_yuv_, "a_texCoord"); |
+ AssertNoGLError(); |
+ gles2_if_->EnableVertexAttribArray(context, pos_location); |
+ gles2_if_->VertexAttribPointer(context, pos_location, 2, |
+ GL_FLOAT, GL_FALSE, 0, 0); |
+ gles2_if_->EnableVertexAttribArray(context, tc_location); |
+ gles2_if_->VertexAttribPointer( |
+ context, tc_location, 2, GL_FLOAT, GL_FALSE, 0, |
+ static_cast<float*>(0) + 16); // Skip position coordinates. |
+ AssertNoGLError(); |
+ |
+ gles2_if_->DrawArrays(context, GL_TRIANGLE_STRIP, 0, 4); |
+ AssertNoGLError(); |
+} |
+ |
+void MediaStreamVideoDemoInstance::DrawRGB() { |
+ PP_Resource context = context_->pp_resource(); |
+ gles2_if_->UseProgram(context, program_rgb_); |
+ gles2_if_->Uniform1i(context, |
+ gles2_if_->GetUniformLocation(context, program_rgb_, "rgb_texture"), 3); |
+ AssertNoGLError(); |
+ |
+ GLint pos_location = gles2_if_->GetAttribLocation( |
+ context, program_rgb_, "a_position"); |
+ GLint tc_location = gles2_if_->GetAttribLocation( |
+ context, program_rgb_, "a_texCoord"); |
+ AssertNoGLError(); |
+ gles2_if_->EnableVertexAttribArray(context, pos_location); |
+ gles2_if_->VertexAttribPointer(context, pos_location, 2, |
+ GL_FLOAT, GL_FALSE, 0, 0); |
+ gles2_if_->EnableVertexAttribArray(context, tc_location); |
+ gles2_if_->VertexAttribPointer( |
+ context, tc_location, 2, GL_FLOAT, GL_FALSE, 0, |
+ static_cast<float*>(0) + 16); // Skip position coordinates. |
+ AssertNoGLError(); |
+ |
+ gles2_if_->DrawArrays(context, GL_TRIANGLE_STRIP, 4, 4); |
+} |
+ |
void MediaStreamVideoDemoInstance::Render() { |
PP_DCHECK(!is_painting_); |
is_painting_ = true; |
needs_paint_ = false; |
+ |
if (texture_y_) { |
- gles2_if_->DrawArrays(context_->pp_resource(), GL_TRIANGLE_STRIP, 0, 4); |
+ DrawRGB(); |
+ DrawYUV(); |
} else { |
gles2_if_->Clear(context_->pp_resource(), GL_COLOR_BUFFER_BIT); |
} |
@@ -194,10 +302,11 @@ void MediaStreamVideoDemoInstance::PaintFinished(int32_t result) { |
} |
GLuint MediaStreamVideoDemoInstance::CreateTexture( |
- int32_t width, int32_t height, int unit) { |
+ int32_t width, int32_t height, int unit, bool rgba) { |
GLuint texture_id; |
gles2_if_->GenTextures(context_->pp_resource(), 1, &texture_id); |
AssertNoGLError(); |
+ |
// Assign parameters. |
gles2_if_->ActiveTexture(context_->pp_resource(), GL_TEXTURE0 + unit); |
gles2_if_->BindTexture(context_->pp_resource(), GL_TEXTURE_2D, texture_id); |
@@ -213,11 +322,12 @@ GLuint MediaStreamVideoDemoInstance::CreateTexture( |
gles2_if_->TexParameterf( |
context_->pp_resource(), GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, |
GL_CLAMP_TO_EDGE); |
- |
// Allocate texture. |
gles2_if_->TexImage2D( |
- context_->pp_resource(), GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, |
- GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL); |
+ context_->pp_resource(), GL_TEXTURE_2D, 0, |
+ rgba ? GL_BGRA_EXT : GL_LUMINANCE, |
+ width, height, 0, |
+ rgba ? GL_BGRA_EXT : GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL); |
AssertNoGLError(); |
return texture_id; |
} |
@@ -234,7 +344,7 @@ void MediaStreamVideoDemoInstance::CreateGLObjects() { |
" gl_Position = a_position; \n" |
"}"; |
- static const char kFragmentShader[] = |
+ static const char kFragmentShaderYUV[] = |
"precision mediump float; \n" |
"varying vec2 v_texCoord; \n" |
"uniform sampler2D y_texture; \n" |
@@ -251,60 +361,48 @@ void MediaStreamVideoDemoInstance::CreateGLObjects() { |
" gl_FragColor = vec4(rgb, 1.0); \n" |
"}"; |
- static const float kColorMatrix[9] = { |
- 1.1643828125f, 1.1643828125f, 1.1643828125f, |
- 0.0f, -0.39176171875f, 2.017234375f, |
- 1.59602734375f, -0.81296875f, 0.0f |
- }; |
+ static const char kFragmentShaderRGB[] = |
+ "precision mediump float; \n" |
+ "varying vec2 v_texCoord; \n" |
+ "uniform sampler2D rgb_texture; \n" |
+ "void main() \n" |
+ "{ \n" |
+ " gl_FragColor = texture2D(rgb_texture, v_texCoord); \n" |
+ "}"; |
PP_Resource context = context_->pp_resource(); |
- // Create shader program. |
- GLuint program = gles2_if_->CreateProgram(context); |
- CreateShader(program, GL_VERTEX_SHADER, kVertexShader, sizeof(kVertexShader)); |
- CreateShader( |
- program, GL_FRAGMENT_SHADER, kFragmentShader, sizeof(kFragmentShader)); |
- gles2_if_->LinkProgram(context, program); |
- gles2_if_->UseProgram(context, program); |
- gles2_if_->DeleteProgram(context, program); |
- gles2_if_->Uniform1i( |
- context, gles2_if_->GetUniformLocation(context, program, "y_texture"), 0); |
- gles2_if_->Uniform1i( |
- context, gles2_if_->GetUniformLocation(context, program, "u_texture"), 1); |
- gles2_if_->Uniform1i( |
- context, gles2_if_->GetUniformLocation(context, program, "v_texture"), 2); |
- gles2_if_->UniformMatrix3fv( |
- context, |
- gles2_if_->GetUniformLocation(context, program, "color_matrix"), |
- 1, GL_FALSE, kColorMatrix); |
+ // Create shader programs. |
+ program_yuv_ = gles2_if_->CreateProgram(context); |
+ CreateShader(program_yuv_, GL_VERTEX_SHADER, |
+ kVertexShader, sizeof(kVertexShader)); |
+ CreateShader(program_yuv_, GL_FRAGMENT_SHADER, |
+ kFragmentShaderYUV, sizeof(kFragmentShaderYUV)); |
+ gles2_if_->LinkProgram(context, program_yuv_); |
+ AssertNoGLError(); |
+ |
+ program_rgb_ = gles2_if_->CreateProgram(context); |
+ CreateShader(program_rgb_, GL_VERTEX_SHADER, |
+ kVertexShader, sizeof(kVertexShader)); |
+ CreateShader(program_rgb_, GL_FRAGMENT_SHADER, |
+ kFragmentShaderRGB, sizeof(kFragmentShaderRGB)); |
+ gles2_if_->LinkProgram(context, program_rgb_); |
AssertNoGLError(); |
// 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. |
+ -1, 1, -1, -1, 0, 1, 0, -1, // Position coordinates. |
+ 0, 1, 0, -1, 1, 1, 1, -1, // Position coordinates. |
+ 0, 0, 0, 1, 1, 0, 1, 1, // Texture coordinates. |
0, 0, 0, 1, 1, 0, 1, 1, // Texture coordinates. |
}; |
- GLuint buffer; |
- gles2_if_->GenBuffers(context, 1, &buffer); |
- gles2_if_->BindBuffer(context, GL_ARRAY_BUFFER, buffer); |
+ gles2_if_->GenBuffers(context, 1, &buffer_); |
+ gles2_if_->BindBuffer(context, GL_ARRAY_BUFFER, buffer_); |
gles2_if_->BufferData(context, GL_ARRAY_BUFFER, |
sizeof(kVertices), kVertices, GL_STATIC_DRAW); |
AssertNoGLError(); |
- GLint pos_location = gles2_if_->GetAttribLocation( |
- context, program, "a_position"); |
- GLint tc_location = gles2_if_->GetAttribLocation( |
- context, program, "a_texCoord"); |
- AssertNoGLError(); |
- gles2_if_->EnableVertexAttribArray(context, pos_location); |
- gles2_if_->VertexAttribPointer(context, pos_location, 2, |
- GL_FLOAT, GL_FALSE, 0, 0); |
- gles2_if_->EnableVertexAttribArray(context, tc_location); |
- gles2_if_->VertexAttribPointer( |
- context, tc_location, 2, GL_FLOAT, GL_FALSE, 0, |
- static_cast<float*>(0) + 8); // Skip position coordinates. |
- AssertNoGLError(); |
} |
void MediaStreamVideoDemoInstance::CreateShader( |
@@ -317,7 +415,7 @@ void MediaStreamVideoDemoInstance::CreateShader( |
gles2_if_->DeleteShader(context, shader); |
} |
-void MediaStreamVideoDemoInstance::CreateYUVTextures() { |
+void MediaStreamVideoDemoInstance::CreateTextures() { |
int32_t width = frame_size_.width(); |
int32_t height = frame_size_.height(); |
if (width == 0 || height == 0) |
@@ -328,12 +426,18 @@ void MediaStreamVideoDemoInstance::CreateYUVTextures() { |
gles2_if_->DeleteTextures(context_->pp_resource(), 1, &texture_u_); |
if (texture_v_) |
gles2_if_->DeleteTextures(context_->pp_resource(), 1, &texture_v_); |
- texture_y_ = CreateTexture(width, height, 0); |
+ if (texture_rgb_) |
+ gles2_if_->DeleteTextures(context_->pp_resource(), 1, &texture_rgb_); |
+ texture_y_ = CreateTexture(width, height, 0, false); |
- width /= 2; |
- height /= 2; |
- texture_u_ = CreateTexture(width, height, 1); |
- texture_v_ = CreateTexture(width, height, 2); |
+ texture_u_ = CreateTexture(width / 2, height / 2, 1, false); |
+ texture_v_ = CreateTexture(width / 2, height / 2, 2, false); |
+ texture_rgb_ = CreateTexture(width, height, 3, true); |
+} |
+ |
+void MediaStreamVideoDemoInstance::OnConfigure(int32_t result) { |
+ video_track_.GetFrame(callback_factory_.NewCallbackWithOutput( |
+ &MediaStreamVideoDemoInstance::OnGetFrame)); |
} |
void MediaStreamVideoDemoInstance::OnGetFrame( |
@@ -346,30 +450,39 @@ void MediaStreamVideoDemoInstance::OnGetFrame( |
if (size != frame_size_) { |
frame_size_ = size; |
- CreateYUVTextures(); |
+ CreateTextures(); |
} |
+ is_bgra_ = (frame.GetFormat() == PP_VIDEOFRAME_FORMAT_BGRA); |
+ |
int32_t width = frame_size_.width(); |
int32_t height = frame_size_.height(); |
- gles2_if_->ActiveTexture(context_->pp_resource(), GL_TEXTURE0); |
- gles2_if_->TexSubImage2D( |
- context_->pp_resource(), GL_TEXTURE_2D, 0, 0, 0, width, height, |
- GL_LUMINANCE, GL_UNSIGNED_BYTE, data); |
- |
- data += width * height; |
- width /= 2; |
- height /= 2; |
- |
- gles2_if_->ActiveTexture(context_->pp_resource(), GL_TEXTURE1); |
- gles2_if_->TexSubImage2D( |
- context_->pp_resource(), GL_TEXTURE_2D, 0, 0, 0, width, height, |
- GL_LUMINANCE, GL_UNSIGNED_BYTE, data); |
- |
- data += width * height; |
- gles2_if_->ActiveTexture(context_->pp_resource(), GL_TEXTURE2); |
- gles2_if_->TexSubImage2D( |
- context_->pp_resource(), GL_TEXTURE_2D, 0, 0, 0, width, height, |
- GL_LUMINANCE, GL_UNSIGNED_BYTE, data); |
+ if (!is_bgra_) { |
+ gles2_if_->ActiveTexture(context_->pp_resource(), GL_TEXTURE0); |
+ gles2_if_->TexSubImage2D( |
+ context_->pp_resource(), GL_TEXTURE_2D, 0, 0, 0, width, height, |
+ GL_LUMINANCE, GL_UNSIGNED_BYTE, data); |
+ |
+ data += width * height; |
+ width /= 2; |
+ height /= 2; |
+ |
+ gles2_if_->ActiveTexture(context_->pp_resource(), GL_TEXTURE1); |
+ gles2_if_->TexSubImage2D( |
+ context_->pp_resource(), GL_TEXTURE_2D, 0, 0, 0, width, height, |
+ GL_LUMINANCE, GL_UNSIGNED_BYTE, data); |
+ |
+ data += width * height; |
+ gles2_if_->ActiveTexture(context_->pp_resource(), GL_TEXTURE2); |
+ gles2_if_->TexSubImage2D( |
+ context_->pp_resource(), GL_TEXTURE_2D, 0, 0, 0, width, height, |
+ GL_LUMINANCE, GL_UNSIGNED_BYTE, data); |
+ } else { |
+ gles2_if_->ActiveTexture(context_->pp_resource(), GL_TEXTURE3); |
+ gles2_if_->TexSubImage2D( |
+ context_->pp_resource(), GL_TEXTURE_2D, 0, 0, 0, width, height, |
+ GL_BGRA_EXT, GL_UNSIGNED_BYTE, data); |
+ } |
if (is_painting_) |
needs_paint_ = true; |
@@ -377,8 +490,14 @@ void MediaStreamVideoDemoInstance::OnGetFrame( |
Render(); |
video_track_.RecycleFrame(frame); |
- video_track_.GetFrame(callback_factory_.NewCallbackWithOutput( |
- &MediaStreamVideoDemoInstance::OnGetFrame)); |
+ if (attrib_list_.empty()) { |
+ video_track_.GetFrame(callback_factory_.NewCallbackWithOutput( |
+ &MediaStreamVideoDemoInstance::OnGetFrame)); |
+ } else { |
+ video_track_.Configure(attrib_list_.data(), callback_factory_.NewCallback( |
+ &MediaStreamVideoDemoInstance::OnConfigure)); |
+ attrib_list_.clear(); |
+ } |
} |
pp::Instance* MediaStreamVideoModule::CreateInstance(PP_Instance instance) { |