Chromium Code Reviews| Index: ppapi/examples/gles2/gles2.cc |
| diff --git a/ppapi/examples/gles2/gles2.cc b/ppapi/examples/gles2/gles2.cc |
| index 70c6596fa84acf4163f7f1b6fbe4cf2b7f0721ae..cffa96bcd3f7dd62c1996e600dcefbad10e73c22 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(); |
| + // State of a single decoder. |
| + class DecoderState { |
|
vrk (LEFT CHROMIUM)
2011/08/16 23:53:11
nit: change class name + comment? Feels like there
Ami GONE FROM CHROMIUM
2011/08/17 00:01:58
I'm not crazy about it, but s/state/done/g
|
| + public: |
| + DecoderState(GLES2DemoInstance* gles2, pp::VideoDecoder_Dev* decoder); |
| + ~DecoderState(); |
| + |
| + // Decode helpers. |
| + void DecodeNextNALUs(); |
| + void DecodeNextNALU(); |
|
vrk (LEFT CHROMIUM)
2011/08/16 23:53:11
I think this and the next 3 methods can be private
Ami GONE FROM CHROMIUM
2011/08/17 00:01:58
Done.
|
| + 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); |
| - // 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); |
|
vrk (LEFT CHROMIUM)
2011/08/16 23:53:11
nit: indentation
Ami GONE FROM CHROMIUM
2011/08/17 00:01:58
Done.
|
| + 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: |
| + GLES2DemoInstance* gles2_; |
| + pp::VideoDecoder_Dev* decoder_; |
| + pp::CompletionCallbackFactory<DecoderState> 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, DecoderState*> Decoders; |
| + Decoders video_decoders_; |
| +}; |
| + |
| +GLES2DemoInstance::DecoderState::DecoderState(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::DecoderState::~DecoderState() { |
| + 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) { |
| + DecoderState* state = new DecoderState( |
| + this, new pp::VideoDecoder_Dev(*this, *context_, &configs)); |
| + assert(!state->decoder()->is_null()); |
| + assert(video_decoders_.insert(std::make_pair( |
| + state->decoder()->pp_resource(), state)).second); |
| + state->DecodeNextNALUs(); |
| + } |
| } |
| -void GLES2DemoInstance::DecoderBitstreamDone( |
| +void GLES2DemoInstance::DecoderState::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::DecoderState::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::DecoderState::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::DecoderState::DecodeNextNALUs() { |
| while (encoded_data_next_pos_to_decode_ <= kDataLen && |
| bitstream_ids_at_decoder_.size() < kNumConcurrentDecodes) { |
| DecodeNextNALU(); |
| } |
| } |
| -void GLES2DemoInstance::DecodeNextNALU() { |
| +void GLES2DemoInstance::DecoderState::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::DecoderState::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::DecoderState::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()); |
| + DecoderState* state = video_decoders_[decoder]; |
| + assert(state); |
| + state->ProvidePictureBuffers(req_num_of_bufs, dimensions); |
| +} |
| + |
| +void GLES2DemoInstance::DecoderState::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::DecoderState::GetPictureBufferById( |
| + int id) { |
|
vrk (LEFT CHROMIUM)
2011/08/16 23:53:11
nit: indentation (put on line above)
|
| + 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); |
| + DecoderState* state = video_decoders_[decoder]; |
| + assert(state); |
| + state->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::DecoderState::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; |
| + DecoderState* state = video_decoders_[decoder]; |
| + assert(state); |
| + const PP_PictureBuffer_Dev& buffer = |
| + state->GetPictureBufferById(picture.picture_buffer_id); |
| assert(!is_painting_); |
| is_painting_ = true; |
| + int x = 0; |
| + int y = 0; |
| + if (state != 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); |
| + DecoderState* state = video_decoders_[decoder]; |
| + if (state && state->decoder()) |
| + state->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); |
| } |
| } |