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..0dbf1bdae104a3e510ca15eefff7cdf5db5ee778 100644 |
| --- a/ppapi/examples/gles2/gles2.cc |
| +++ b/ppapi/examples/gles2/gles2.cc |
| @@ -73,20 +73,39 @@ class GLES2DemoInstance : public pp::Instance, |
| private: |
| enum { kNumConcurrentDecodes = 7 }; |
| - // Initialize Video Decoder. |
| - void InitializeDecoder(); |
| - |
| - // 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); |
| + // State of a single decoder. |
| + struct DecoderState { |
| + DecoderState(GLES2DemoInstance* gles2, pp::VideoDecoder_Dev* decoder); |
| + ~DecoderState(); |
| + |
| + // Cleanup helpers. |
| + void DeleteOutstandingBitstreamBuffers(); |
| + void DeleteOutstandingTextures(); |
| + |
| + // Decode helpers. |
| + void DecodeNextNALUs(); |
| + 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<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 buffers_by_id_; |
| + // Map of bitstream buffers indexed by id. |
| + typedef std::map<int, pp::Buffer_Dev*> BitstreamBufferMap; |
| + BitstreamBufferMap bitstream_buffers_by_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(); |
| + // Initialize Video Decoders. |
| + void InitializeDecoders(); |
| // GL-related functions. |
| void InitGL(); |
| @@ -94,8 +113,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 |
| @@ -120,26 +139,15 @@ class GLES2DemoInstance : public pp::Instance, |
| }; |
| pp::Size position_size_; |
|
vrk (LEFT CHROMIUM)
2011/08/16 22:06:21
nit: rename position_size_ to viewport_size_? (If
Ami GONE FROM CHROMIUM
2011/08/16 22:56:26
It's not.
The size is that of the position argumen
|
| - int next_picture_buffer_id_; |
| - int next_bitstream_buffer_id_; |
| 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 +157,47 @@ 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; |
| +} |
| + |
| +void GLES2DemoInstance::DecoderState::DeleteOutstandingTextures() { |
| + for (PictureBufferMap::iterator it = buffers_by_id_.begin(); |
| + it != buffers_by_id_.end(); ++it) { |
| + gles2_->DeleteTexture(it->second.texture_id); |
| + } |
| + buffers_by_id_.clear(); |
| +} |
| + |
| +void GLES2DemoInstance::DecoderState::DeleteOutstandingBitstreamBuffers() { |
| + for (BitstreamBufferMap::iterator it = bitstream_buffers_by_id_.begin(); |
| + it != bitstream_buffers_by_id_.end(); ++it) { |
| + delete it->second; |
| + } |
| + bitstream_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,27 +207,15 @@ 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) { |
| + it->second->DeleteOutstandingBitstreamBuffers(); |
|
vrk (LEFT CHROMIUM)
2011/08/16 22:06:21
Any reason not to push these DeleteOutstandingBits
Ami GONE FROM CHROMIUM
2011/08/16 22:56:26
Done (and in-lined).
|
| + it->second->DeleteOutstandingTextures(); |
| delete it->second; |
| } |
| - bitstream_buffers_by_id_.clear(); |
| + video_decoders_.clear(); |
| + delete surface_; |
| + delete context_; |
| } |
| void GLES2DemoInstance::DidChangeView( |
| @@ -209,20 +230,24 @@ void GLES2DemoInstance::DidChangeView( |
| // 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 < 2; ++i) { |
|
vrk (LEFT CHROMIUM)
2011/08/16 22:06:21
Instead of 2, make into an enum constant? (like kN
Ami GONE FROM CHROMIUM
2011/08/16 22:56:26
Done.
(I previously hadn't b/c the /2 was still ha
|
| + DecoderState* state = new DecoderState( |
| + this, new pp::VideoDecoder_Dev(*this, *context_, &configs)); |
| + assert(!state->decoder_->is_null()); |
|
vrk (LEFT CHROMIUM)
2011/08/16 22:06:21
If you're going the DecoderClient route, could pro
Ami GONE FROM CHROMIUM
2011/08/16 22:56:26
Done.
|
| + 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 +258,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 +273,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 +288,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 +317,79 @@ 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()); |
| std::vector<PP_PictureBuffer_Dev> buffers; |
| - for (uint32_t i = 0; i < req_num_of_bufs; i++) { |
| + DecoderState* state = video_decoders_[decoder]; |
| + assert(state); |
| + for (uint32_t i = 0; i < req_num_of_bufs; ++i) { |
|
vrk (LEFT CHROMIUM)
2011/08/16 22:06:21
Put this behavior in DecoderState object if not to
Ami GONE FROM CHROMIUM
2011/08/16 22:56:26
Done.
|
| PP_PictureBuffer_Dev buffer; |
| buffer.texture_id = CreateTexture(dimensions.width, dimensions.height); |
| - int id = ++next_picture_buffer_id_; |
| + int id = ++state->next_picture_buffer_id_; |
| buffer.id = id; |
| buffers.push_back(buffer); |
| - assert(buffers_by_id_.insert(std::make_pair(id, buffer)).second); |
| + assert(state->buffers_by_id_.insert(std::make_pair(id, buffer)).second); |
| } |
| - video_decoder_->AssignPictureBuffers(buffers); |
| + state->decoder_->AssignPictureBuffers(buffers); |
| } |
| 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()); |
| + DecoderState* state = video_decoders_[decoder]; |
| + assert(state); |
| + DecoderState::PictureBufferMap::iterator it = |
|
vrk (LEFT CHROMIUM)
2011/08/16 22:06:21
Put this behavior in DecoderState object if not to
Ami GONE FROM CHROMIUM
2011/08/16 22:56:26
Done.
|
| + state->buffers_by_id_.find(picture_buffer_id); |
| + assert(it != state->buffers_by_id_.end()); |
| DeleteTexture(it->second.texture_id); |
| - buffers_by_id_.erase(it); |
| + state->buffers_by_id_.erase(it); |
| } |
| void GLES2DemoInstance::PictureReady(PP_Resource decoder, |
| const PP_Picture_Dev& picture) { |
| - assert(decoder == video_decoder_->pp_resource()); |
| - PaintStart(picture); |
| -} |
| - |
| -void GLES2DemoInstance::PaintStart(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()); |
| + DecoderState* state = video_decoders_[decoder]; |
| + assert(state); |
| + DecoderState::PictureBufferMap::iterator it = |
|
vrk (LEFT CHROMIUM)
2011/08/16 22:06:21
If you're going the DecoderClient route, smush thi
Ami GONE FROM CHROMIUM
2011/08/16 22:56:26
Done.
|
| + state->buffers_by_id_.find(picture.picture_buffer_id); |
| + assert(it != state->buffers_by_id_.end()); |
| const PP_PictureBuffer_Dev& buffer = it->second; |
| assert(!is_painting_); |
| is_painting_ = true; |
| + int x = 0; |
| + int y = 0; |
| + if (state != video_decoders_.begin()->second) { |
| + x = position_size_.width() / 2; |
| + y = position_size_.height() / 2; |
| + } |
| + gles2_if_->Viewport(context_->pp_resource(), x, y, |
| + position_size_.width() / 2, position_size_.height() / 2); |
| 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"); |
| } |
| @@ -392,10 +424,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 +433,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 +446,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_) |
|
vrk (LEFT CHROMIUM)
2011/08/16 22:06:21
If you're going the DecoderClient route, here too
Ami GONE FROM CHROMIUM
2011/08/16 22:56:26
Done.
|
| + 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); |
| } |
| } |