summaryrefslogtreecommitdiffstats
path: root/ppapi/examples
diff options
context:
space:
mode:
authorfischman@chromium.org <fischman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-17 00:17:23 +0000
committerfischman@chromium.org <fischman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-17 00:17:23 +0000
commit502e605ef343c8948a3fe6fc0e36907b9a3f3dba (patch)
treebc62519e2f4052d4179fe9742e6a5ee8401ea481 /ppapi/examples
parentb3b99ab894881437f25be277aa8f7ab52e50be54 (diff)
downloadchromium_src-502e605ef343c8948a3fe6fc0e36907b9a3f3dba.zip
chromium_src-502e605ef343c8948a3fe6fc0e36907b9a3f3dba.tar.gz
chromium_src-502e605ef343c8948a3fe6fc0e36907b9a3f3dba.tar.bz2
Support multiple HW video decoders per context.
Enhanced gles2.cc to display two decoders in the same context to demo this capability. BUG=92598 TEST=ovdatest passes, gles2 works, trybots Review URL: http://codereview.chromium.org/7659001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@97066 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi/examples')
-rw-r--r--ppapi/examples/gles2/gles2.cc276
-rw-r--r--ppapi/examples/gles2/gles2.html2
2 files changed, 164 insertions, 114 deletions
diff --git a/ppapi/examples/gles2/gles2.cc b/ppapi/examples/gles2/gles2.cc
index 70c6596..1a3a09b 100644
--- a/ppapi/examples/gles2/gles2.cc
+++ b/ppapi/examples/gles2/gles2.cc
@@ -71,22 +71,48 @@ class GLES2DemoInstance : public pp::Instance,
virtual void NotifyError(PP_Resource decoder, PP_VideoDecodeError_Dev error);
private:
- enum { kNumConcurrentDecodes = 7 };
+ enum { kNumConcurrentDecodes = 7,
+ kNumDecoders = 2 }; // Baked into viewport rendering.
- // Initialize Video Decoder.
- void InitializeDecoder();
+ // A single decoder's client interface.
+ class DecoderClient {
+ public:
+ DecoderClient(GLES2DemoInstance* gles2, pp::VideoDecoder_Dev* decoder);
+ ~DecoderClient();
+
+ void DecodeNextNALUs();
- // Callbacks passed into pp:VideoDecoder_Dev functions.
- void DecoderInitDone(int32_t result);
- void DecoderBitstreamDone(int32_t result, int bitstream_buffer_id);
- void DecoderFlushDone(int32_t result);
+ // Per-decoder implementation of part of pp::VideoDecoderClient_Dev.
+ void ProvidePictureBuffers(uint32_t req_num_of_bufs,
+ PP_Size dimensions);
+ void DismissPictureBuffer(int32_t picture_buffer_id);
- // Decode helpers.
- void DecodeNextNALUs();
- void DecodeNextNALU();
- void GetNextNALUBoundary(size_t start_pos, size_t* end_pos);
- void PaintStart(const PP_Picture_Dev& picture);
- void DeleteOutstandingBitstreamBuffers();
+ const PP_PictureBuffer_Dev& GetPictureBufferById(int id);
+ pp::VideoDecoder_Dev* decoder() { return decoder_; }
+
+ private:
+ void DecodeNextNALU();
+ static void GetNextNALUBoundary(size_t start_pos, size_t* end_pos);
+ void DecoderBitstreamDone(int32_t result, int bitstream_buffer_id);
+ void DecoderFlushDone(int32_t result);
+
+ GLES2DemoInstance* gles2_;
+ pp::VideoDecoder_Dev* decoder_;
+ pp::CompletionCallbackFactory<DecoderClient> callback_factory_;
+ int next_picture_buffer_id_;
+ int next_bitstream_buffer_id_;
+ size_t encoded_data_next_pos_to_decode_;
+ std::set<int> bitstream_ids_at_decoder_;
+ // Map of texture buffers indexed by buffer id.
+ typedef std::map<int, PP_PictureBuffer_Dev> PictureBufferMap;
+ PictureBufferMap picture_buffers_by_id_;
+ // Map of bitstream buffers indexed by id.
+ typedef std::map<int, pp::Buffer_Dev*> BitstreamBufferMap;
+ BitstreamBufferMap bitstream_buffers_by_id_;
+ };
+
+ // Initialize Video Decoders.
+ void InitializeDecoders();
// GL-related functions.
void InitGL();
@@ -94,8 +120,8 @@ class GLES2DemoInstance : public pp::Instance,
void CreateGLObjects();
void CreateShader(GLuint program, GLenum type, const char* source, int size);
void DeleteTexture(GLuint id);
- void DeleteOutstandingTextures();
- void PaintFinished(int32_t result, int picture_buffer_id);
+ void PaintFinished(int32_t result, PP_Resource decoder,
+ int picture_buffer_id);
// Log an error to the developer console and stderr (though the latter may be
// closed due to sandboxing or blackholed for other reasons) by creating a
@@ -119,27 +145,16 @@ class GLES2DemoInstance : public pp::Instance,
std::ostringstream stream_;
};
- pp::Size position_size_;
- int next_picture_buffer_id_;
- int next_bitstream_buffer_id_;
+ pp::Size plugin_size_;
bool is_painting_;
- pp::CompletionCallbackFactory<GLES2DemoInstance> callback_factory_;
- size_t encoded_data_next_pos_to_decode_;
- std::set<int> bitstream_ids_at_decoder_;
// When decode outpaces render, we queue up decoded pictures for later
- // painting.
- std::list<PP_Picture_Dev> pictures_pending_paint_;
+ // painting. Elements are <decoder,picture>.
+ std::list<std::pair<PP_Resource, PP_Picture_Dev> > pictures_pending_paint_;
int num_frames_rendered_;
-
- // Map of texture buffers indexed by buffer id.
- typedef std::map<int, PP_PictureBuffer_Dev> PictureBufferMap;
- PictureBufferMap buffers_by_id_;
- // Map of bitstream buffers indexed by id.
- typedef std::map<int, pp::Buffer_Dev*> BitstreamBufferMap;
- BitstreamBufferMap bitstream_buffers_by_id_;
PP_TimeTicks first_frame_delivered_ticks_;
PP_TimeTicks last_swap_request_ticks_;
PP_TimeTicks swap_ticks_;
+ pp::CompletionCallbackFactory<GLES2DemoInstance> callback_factory_;
// Unowned pointers.
const struct PPB_Console_Dev* console_if_;
@@ -149,22 +164,43 @@ class GLES2DemoInstance : public pp::Instance,
// Owned data.
pp::Context3D_Dev* context_;
pp::Surface3D_Dev* surface_;
- pp::VideoDecoder_Dev* video_decoder_;
+ typedef std::map<int, DecoderClient*> Decoders;
+ Decoders video_decoders_;
+};
+
+GLES2DemoInstance::DecoderClient::DecoderClient(GLES2DemoInstance* gles2,
+ pp::VideoDecoder_Dev* decoder)
+ : gles2_(gles2), decoder_(decoder), callback_factory_(this),
+ next_picture_buffer_id_(0),
+ next_bitstream_buffer_id_(0), encoded_data_next_pos_to_decode_(0) {
};
+GLES2DemoInstance::DecoderClient::~DecoderClient() {
+ delete decoder_;
+ decoder_ = NULL;
+
+ for (BitstreamBufferMap::iterator it = bitstream_buffers_by_id_.begin();
+ it != bitstream_buffers_by_id_.end(); ++it) {
+ delete it->second;
+ }
+ bitstream_buffers_by_id_.clear();
+
+ for (PictureBufferMap::iterator it = picture_buffers_by_id_.begin();
+ it != picture_buffers_by_id_.end(); ++it) {
+ gles2_->DeleteTexture(it->second.texture_id);
+ }
+ picture_buffers_by_id_.clear();
+}
+
GLES2DemoInstance::GLES2DemoInstance(PP_Instance instance, pp::Module* module)
: pp::Instance(instance), pp::Graphics3DClient_Dev(this),
pp::VideoDecoderClient_Dev(this),
- next_picture_buffer_id_(0),
- next_bitstream_buffer_id_(0),
- callback_factory_(this),
- encoded_data_next_pos_to_decode_(0),
num_frames_rendered_(0),
first_frame_delivered_ticks_(-1),
swap_ticks_(0),
+ callback_factory_(this),
context_(NULL),
- surface_(NULL),
- video_decoder_(NULL) {
+ surface_(NULL) {
assert((console_if_ = static_cast<const struct PPB_Console_Dev*>(
module->GetBrowserInterface(PPB_CONSOLE_DEV_INTERFACE))));
assert((core_if_ = static_cast<const struct PPB_Core*>(
@@ -174,55 +210,45 @@ GLES2DemoInstance::GLES2DemoInstance(PP_Instance instance, pp::Module* module)
}
GLES2DemoInstance::~GLES2DemoInstance() {
- delete video_decoder_; // May be NULL, which is fine.
- DeleteOutstandingBitstreamBuffers();
- DeleteOutstandingTextures();
- delete surface_;
- delete context_;
-}
-
-void GLES2DemoInstance::DeleteOutstandingTextures() {
- for (PictureBufferMap::iterator it = buffers_by_id_.begin();
- it != buffers_by_id_.end(); ++it) {
- DeleteTexture(it->second.texture_id);
- }
- buffers_by_id_.clear();
-}
-
-void GLES2DemoInstance::DeleteOutstandingBitstreamBuffers() {
- for (BitstreamBufferMap::iterator it = bitstream_buffers_by_id_.begin();
- it != bitstream_buffers_by_id_.end(); ++it) {
+ for (Decoders::iterator it = video_decoders_.begin();
+ it != video_decoders_.end(); ++it) {
delete it->second;
}
- bitstream_buffers_by_id_.clear();
+ video_decoders_.clear();
+ delete surface_;
+ delete context_;
}
void GLES2DemoInstance::DidChangeView(
const pp::Rect& position, const pp::Rect& clip_ignored) {
if (position.width() == 0 || position.height() == 0)
return;
- if (position_size_.width()) {
- assert(position.size() == position_size_);
+ if (plugin_size_.width()) {
+ assert(position.size() == plugin_size_);
return;
}
- position_size_ = position.size();
+ plugin_size_ = position.size();
// Initialize graphics.
InitGL();
- InitializeDecoder();
+ InitializeDecoders();
}
-void GLES2DemoInstance::InitializeDecoder() {
+void GLES2DemoInstance::InitializeDecoders() {
PP_VideoConfigElement configs = PP_VIDEOATTR_DICTIONARY_TERMINATOR;
- assert(!video_decoder_);
- video_decoder_ = new pp::VideoDecoder_Dev(*this, *context_, &configs);
- assert(!video_decoder_->is_null());
-
- DecodeNextNALUs();
+ assert(video_decoders_.empty());
+ for (int i = 0; i < kNumDecoders; ++i) {
+ DecoderClient* client = new DecoderClient(
+ this, new pp::VideoDecoder_Dev(*this, *context_, &configs));
+ assert(!client->decoder()->is_null());
+ assert(video_decoders_.insert(std::make_pair(
+ client->decoder()->pp_resource(), client)).second);
+ client->DecodeNextNALUs();
+ }
}
-void GLES2DemoInstance::DecoderBitstreamDone(
+void GLES2DemoInstance::DecoderClient::DecoderBitstreamDone(
int32_t result, int bitstream_buffer_id) {
assert(bitstream_ids_at_decoder_.erase(bitstream_buffer_id) == 1);
BitstreamBufferMap::iterator it =
@@ -233,12 +259,13 @@ void GLES2DemoInstance::DecoderBitstreamDone(
DecodeNextNALUs();
}
-void GLES2DemoInstance::DecoderFlushDone(int32_t result) {
+void GLES2DemoInstance::DecoderClient::DecoderFlushDone(int32_t result) {
+ assert(result == PP_OK);
// Check that each bitstream buffer ID we handed to the decoder got handed
// back to us.
assert(bitstream_ids_at_decoder_.empty());
- delete video_decoder_;
- video_decoder_ = NULL;
+ delete decoder_;
+ decoder_ = NULL;
}
static bool LookingAtNAL(const unsigned char* encoded, size_t pos) {
@@ -247,7 +274,7 @@ static bool LookingAtNAL(const unsigned char* encoded, size_t pos) {
encoded[pos + 2] == 0 && encoded[pos + 3] == 1;
}
-void GLES2DemoInstance::GetNextNALUBoundary(
+void GLES2DemoInstance::DecoderClient::GetNextNALUBoundary(
size_t start_pos, size_t* end_pos) {
assert(LookingAtNAL(kData, start_pos));
*end_pos = start_pos;
@@ -262,25 +289,25 @@ void GLES2DemoInstance::GetNextNALUBoundary(
}
}
-void GLES2DemoInstance::DecodeNextNALUs() {
+void GLES2DemoInstance::DecoderClient::DecodeNextNALUs() {
while (encoded_data_next_pos_to_decode_ <= kDataLen &&
bitstream_ids_at_decoder_.size() < kNumConcurrentDecodes) {
DecodeNextNALU();
}
}
-void GLES2DemoInstance::DecodeNextNALU() {
+void GLES2DemoInstance::DecoderClient::DecodeNextNALU() {
if (encoded_data_next_pos_to_decode_ == kDataLen) {
++encoded_data_next_pos_to_decode_;
- pp::CompletionCallback cb =
- callback_factory_.NewCallback(&GLES2DemoInstance::DecoderFlushDone);
- video_decoder_->Flush(cb);
+ pp::CompletionCallback cb = callback_factory_.NewCallback(
+ &GLES2DemoInstance::DecoderClient::DecoderFlushDone);
+ decoder_->Flush(cb);
return;
}
size_t start_pos = encoded_data_next_pos_to_decode_;
size_t end_pos;
GetNextNALUBoundary(start_pos, &end_pos);
- pp::Buffer_Dev* buffer = new pp::Buffer_Dev(this, end_pos - start_pos);
+ pp::Buffer_Dev* buffer = new pp::Buffer_Dev(gles2_, end_pos - start_pos);
PP_VideoBitstreamBuffer_Dev bitstream_buffer;
int id = ++next_bitstream_buffer_id_;
bitstream_buffer.id = id;
@@ -291,73 +318,95 @@ void GLES2DemoInstance::DecodeNextNALU() {
pp::CompletionCallback cb =
callback_factory_.NewCallback(
- &GLES2DemoInstance::DecoderBitstreamDone, id);
+ &GLES2DemoInstance::DecoderClient::DecoderBitstreamDone, id);
assert(bitstream_ids_at_decoder_.insert(id).second);
- video_decoder_->Decode(bitstream_buffer, cb);
encoded_data_next_pos_to_decode_ = end_pos;
+ decoder_->Decode(bitstream_buffer, cb);
}
void GLES2DemoInstance::ProvidePictureBuffers(
PP_Resource decoder, uint32_t req_num_of_bufs, PP_Size dimensions) {
- assert(decoder == video_decoder_->pp_resource());
+ DecoderClient* client = video_decoders_[decoder];
+ assert(client);
+ client->ProvidePictureBuffers(req_num_of_bufs, dimensions);
+}
+
+void GLES2DemoInstance::DecoderClient::ProvidePictureBuffers(
+ uint32_t req_num_of_bufs, PP_Size dimensions) {
std::vector<PP_PictureBuffer_Dev> buffers;
- for (uint32_t i = 0; i < req_num_of_bufs; i++) {
+ for (uint32_t i = 0; i < req_num_of_bufs; ++i) {
PP_PictureBuffer_Dev buffer;
- buffer.texture_id = CreateTexture(dimensions.width, dimensions.height);
+ buffer.size = dimensions;
+ buffer.texture_id =
+ gles2_->CreateTexture(dimensions.width, dimensions.height);
int id = ++next_picture_buffer_id_;
buffer.id = id;
buffers.push_back(buffer);
- assert(buffers_by_id_.insert(std::make_pair(id, buffer)).second);
+ assert(picture_buffers_by_id_.insert(std::make_pair(id, buffer)).second);
}
- video_decoder_->AssignPictureBuffers(buffers);
+ decoder_->AssignPictureBuffers(buffers);
+}
+
+const PP_PictureBuffer_Dev&
+GLES2DemoInstance::DecoderClient::GetPictureBufferById(
+ int id) {
+ PictureBufferMap::iterator it = picture_buffers_by_id_.find(id);
+ assert(it != picture_buffers_by_id_.end());
+ return it->second;
}
void GLES2DemoInstance::DismissPictureBuffer(PP_Resource decoder,
int32_t picture_buffer_id) {
- assert(decoder == video_decoder_->pp_resource());
- PictureBufferMap::iterator it = buffers_by_id_.find(picture_buffer_id);
- assert(it != buffers_by_id_.end());
- DeleteTexture(it->second.texture_id);
- buffers_by_id_.erase(it);
+ DecoderClient* client = video_decoders_[decoder];
+ assert(client);
+ client->DismissPictureBuffer(picture_buffer_id);
}
-void GLES2DemoInstance::PictureReady(PP_Resource decoder,
- const PP_Picture_Dev& picture) {
- assert(decoder == video_decoder_->pp_resource());
- PaintStart(picture);
+void GLES2DemoInstance::DecoderClient::DismissPictureBuffer(
+ int32_t picture_buffer_id) {
+ gles2_->DeleteTexture(GetPictureBufferById(picture_buffer_id).texture_id);
+ picture_buffers_by_id_.erase(picture_buffer_id);
}
-void GLES2DemoInstance::PaintStart(const PP_Picture_Dev& picture) {
+void GLES2DemoInstance::PictureReady(PP_Resource decoder,
+ const PP_Picture_Dev& picture) {
if (first_frame_delivered_ticks_ == -1)
assert((first_frame_delivered_ticks_ = core_if_->GetTimeTicks()) != -1);
if (is_painting_) {
- pictures_pending_paint_.push_back(picture);
+ pictures_pending_paint_.push_back(std::make_pair(decoder, picture));
return;
}
- PictureBufferMap::iterator it =
- buffers_by_id_.find(picture.picture_buffer_id);
- assert(it != buffers_by_id_.end());
- const PP_PictureBuffer_Dev& buffer = it->second;
+ DecoderClient* client = video_decoders_[decoder];
+ assert(client);
+ const PP_PictureBuffer_Dev& buffer =
+ client->GetPictureBufferById(picture.picture_buffer_id);
assert(!is_painting_);
is_painting_ = true;
+ int x = 0;
+ int y = 0;
+ if (client != video_decoders_.begin()->second) {
+ x = plugin_size_.width() / kNumDecoders;
+ y = plugin_size_.height() / kNumDecoders;
+ }
+ gles2_if_->Viewport(context_->pp_resource(), x, y,
+ plugin_size_.width() / kNumDecoders,
+ plugin_size_.height() / kNumDecoders);
gles2_if_->ActiveTexture(context_->pp_resource(), GL_TEXTURE0);
gles2_if_->BindTexture(
context_->pp_resource(), GL_TEXTURE_2D, buffer.texture_id);
gles2_if_->DrawArrays(context_->pp_resource(), GL_TRIANGLE_STRIP, 0, 4);
pp::CompletionCallback cb =
callback_factory_.NewCallback(
- &GLES2DemoInstance::PaintFinished, buffer.id);
+ &GLES2DemoInstance::PaintFinished, decoder, buffer.id);
last_swap_request_ticks_ = core_if_->GetTimeTicks();
assert(surface_->SwapBuffers(cb) == PP_OK_COMPLETIONPENDING);
}
void GLES2DemoInstance::EndOfStream(PP_Resource decoder) {
- assert(decoder == video_decoder_->pp_resource());
}
void GLES2DemoInstance::NotifyError(PP_Resource decoder,
PP_VideoDecodeError_Dev error) {
- assert(decoder == video_decoder_->pp_resource());
LogError(this).s() << "Received error: " << error;
assert(!"Unexpected error; see stderr for details");
}
@@ -375,7 +424,7 @@ class GLES2DemoModule : public pp::Module {
};
void GLES2DemoInstance::InitGL() {
- assert(position_size_.width() && position_size_.height());
+ assert(plugin_size_.width() && plugin_size_.height());
is_painting_ = false;
assert(!context_ && !surface_);
@@ -383,8 +432,8 @@ void GLES2DemoInstance::InitGL() {
assert(!context_->is_null());
int32_t surface_attributes[] = {
- PP_GRAPHICS3DATTRIB_WIDTH, position_size_.width(),
- PP_GRAPHICS3DATTRIB_HEIGHT, position_size_.height(),
+ PP_GRAPHICS3DATTRIB_WIDTH, plugin_size_.width(),
+ PP_GRAPHICS3DATTRIB_HEIGHT, plugin_size_.height(),
PP_GRAPHICS3DATTRIB_NONE
};
surface_ = new pp::Surface3D_Dev(*this, 0, surface_attributes);
@@ -392,10 +441,8 @@ void GLES2DemoInstance::InitGL() {
assert(!context_->BindSurfaces(*surface_, *surface_));
- // Set viewport window size and clear color bit.
+ // Clear color bit.
gles2_if_->Clear(context_->pp_resource(), GL_COLOR_BUFFER_BIT);
- gles2_if_->Viewport(context_->pp_resource(), 0, 0,
- position_size_.width(), position_size_.height());
assert(BindGraphics(*surface_));
assertNoGLError();
@@ -403,7 +450,8 @@ void GLES2DemoInstance::InitGL() {
CreateGLObjects();
}
-void GLES2DemoInstance::PaintFinished(int32_t result, int picture_buffer_id) {
+void GLES2DemoInstance::PaintFinished(int32_t result, PP_Resource decoder,
+ int picture_buffer_id) {
swap_ticks_ += core_if_->GetTimeTicks() - last_swap_request_ticks_;
is_painting_ = false;
++num_frames_rendered_;
@@ -415,12 +463,14 @@ void GLES2DemoInstance::PaintFinished(int32_t result, int picture_buffer_id) {
<< ", fps: " << fps << ", with average ms/swap of: "
<< ms_per_swap;
}
- if (video_decoder_)
- video_decoder_->ReusePictureBuffer(picture_buffer_id);
+ DecoderClient* client = video_decoders_[decoder];
+ if (client && client->decoder())
+ client->decoder()->ReusePictureBuffer(picture_buffer_id);
if (!pictures_pending_paint_.empty()) {
- PP_Picture_Dev picture = pictures_pending_paint_.front();
+ std::pair<PP_Resource, PP_Picture_Dev> decoder_picture =
+ pictures_pending_paint_.front();
pictures_pending_paint_.pop_front();
- PaintStart(picture);
+ PictureReady(decoder_picture.first, decoder_picture.second);
}
}
diff --git a/ppapi/examples/gles2/gles2.html b/ppapi/examples/gles2/gles2.html
index 887e094..6459fbd 100644
--- a/ppapi/examples/gles2/gles2.html
+++ b/ppapi/examples/gles2/gles2.html
@@ -12,7 +12,7 @@
<body>
<embed id="plugin" type="application/x-ppapi-example-gles2"
- width="320" height="240"/>
+ width="640" height="480"/>
</body>
</html>