From 3a1ea1b4edb97e94f15526971d33a4c208abcd14 Mon Sep 17 00:00:00 2001 From: "sonal.g1@samsung.com" Date: Thu, 22 Jan 2015 19:12:04 +0530 Subject: [PATCH] [Tizen][WebRTC] Fix delivery of Video Frame from encoder A queue has been created to maintain the encoded buffers before they are send to renderer side for further processing. Queue size goes maximum upto 4 in usual scenario. If queue is not used then frames have to be unnecessarily dropped when output buffers are not available. Reviewed by: Min-Soo Koo, Venugopal S M Change-Id: I422a783871e61543052f37bf16b6536ac52829f6 Signed-off-by: sonal.g1@samsung.com --- .../media/tizen/tizen_video_encode_accelerator.cc | 122 ++++++++++++++------- .../media/tizen/tizen_video_encode_accelerator.h | 1 + 2 files changed, 81 insertions(+), 42 deletions(-) diff --git a/tizen_src/impl/content/common/gpu/media/tizen/tizen_video_encode_accelerator.cc b/tizen_src/impl/content/common/gpu/media/tizen/tizen_video_encode_accelerator.cc index 1e4f332..37c2850 100644 --- a/tizen_src/impl/content/common/gpu/media/tizen/tizen_video_encode_accelerator.cc +++ b/tizen_src/impl/content/common/gpu/media/tizen/tizen_video_encode_accelerator.cc @@ -40,11 +40,12 @@ enum { // Arbitrary choice. INITIAL_FRAMERATE = 30, // Until there are non-realtime users, no need for unrequested I-frames. - INPUT_BUFFER_COUNT = 5, // default input buffer counts of omx_h264enc + INPUT_BUFFER_COUNT = 5, // default input buffer counts of omx_h264enc MAX_BUFFERING = 60, MAX_FRAME_RATE = 30, // Max bitrate in bps - MAX_BITRATE = 2000000 + MAX_BITRATE = 2000000, + MAX_OUTPUT_BUFFERS = 30 // Maximum queue size of output buffers }; // Gstreamer elements and names. const char* kEncoderName = "encoder"; @@ -91,6 +92,22 @@ struct TizenVideoEncodeAccelerator::BitstreamBufferRef { GstBuffer* gst_buffer_; }; +struct TizenVideoEncodeAccelerator::OutputBuffer { + explicit OutputBuffer( + GstBuffer* buffer, + bool key_frame) + : buffer_(buffer), + key_frame_(key_frame) {} + + virtual ~OutputBuffer() { + if(buffer_) + gst_buffer_unref(buffer_); + } + + GstBuffer* buffer_; + bool key_frame_; +}; + struct TizenVideoEncodeAccelerator::Impl { Impl(media::VideoEncodeAccelerator::Client* client, scoped_refptr msg_loop) @@ -106,7 +123,7 @@ struct TizenVideoEncodeAccelerator::Impl { is_destroying_(false), can_feed_(false) {} - void DeliverVideoFrame(GstBuffer* buffer, bool key_frame); + void DeliverVideoFrame(); static GstFlowReturn OnEncoded(GstAppSink *sink,gpointer data); static void StartFeed(GstAppSrc *source, guint size, gpointer data); static void StopFeed(GstAppSrc *source, gpointer data); @@ -126,49 +143,63 @@ struct TizenVideoEncodeAccelerator::Impl { volatile bool is_running_; volatile bool is_destroying_; volatile bool can_feed_; + base::RepeatingTimer io_timer_; + std::queue output_buffers_; + base::Lock output_queue_lock_; }; -void TizenVideoEncodeAccelerator::Impl::DeliverVideoFrame(GstBuffer* buffer, - bool key_frame) { +void TizenVideoEncodeAccelerator::Impl::DeliverVideoFrame() { media::BitstreamBuffer* bs_buffer = NULL; - scoped_ptr shm; - scoped_ptr gst_buffer(buffer); + GstBuffer* buffer = NULL; + bool key_frame = false; gsize gstBufferSize = 0; #if GST_VERSION_MAJOR == 1 GstMapInfo map; #endif - if (gst_buffer == NULL) { - LOG(ERROR) << __FUNCTION__ << " Invalid buffer for delivering"; - return; - } - - if (enable_framedrop_ && key_frame) { - enable_framedrop_ = false; - } + scoped_ptr shm; - if (enable_framedrop_) { - DVLOG(2) << "OUTPUT QUEUE IS EMPTY !!!!!!!! DELTA FRAME DROP."; + if(output_buffers_.empty()) return; - } if (encoder_output_queue_.empty()) { - enable_framedrop_ = true; - DVLOG(2) << "OUTPUT QUEUE IS EMPTY !!!!!!!! FRAME DROP."; + // Observed till now that output_buffers_ size does not exceed 4-5. + // Therefore this code will be called in very rare situations. + if(output_buffers_.size() >= MAX_OUTPUT_BUFFERS) { + enable_framedrop_ = true; + TizenVideoEncodeAccelerator::OutputBuffer* drop_buffer = NULL; + { + base::AutoLock auto_lock(output_queue_lock_); + while(!output_buffers_.empty()) { + drop_buffer = output_buffers_.front(); + if (drop_buffer->key_frame_) + break; + output_buffers_.pop(); + gst_buffer_unref(drop_buffer->buffer_); + delete drop_buffer; + } + } + return; + } return; } - + enable_framedrop_ = false; + key_frame = output_buffers_.front()->key_frame_; bs_buffer = &encoder_output_queue_.back(); encoder_output_queue_.pop_back(); - DVLOG(3) << __FUNCTION__ - << " output buffer in use : buffer_id: " << bs_buffer->id() - << " queue size: " << encoder_output_queue_.size(); - shm.reset(new base::SharedMemory(bs_buffer->handle(), false)); if (!shm->Map(bs_buffer->size())) { LOG(ERROR) << "Failed to map SHM"; - return; + io_client_weak_factory_.GetWeakPtr()->NotifyError( + media::VideoEncodeAccelerator::kPlatformFailureError); + gst_buffer_unref(buffer); + } + + { + base::AutoLock auto_lock(output_queue_lock_); + buffer = output_buffers_.front()->buffer_; + output_buffers_.pop(); } #if GST_VERSION_MAJOR == 1 if (!gst_buffer_map(buffer, &map, GST_MAP_READ)) { @@ -177,20 +208,22 @@ void TizenVideoEncodeAccelerator::Impl::DeliverVideoFrame(GstBuffer* buffer, } gstBufferSize = map.size; #else - gstBufferSize = gst_buffer->size; + gstBufferSize = buffer->size; #endif + if (gstBufferSize > shm->mapped_size()) { - LOG(ERROR) << "Encoded buff too large: " - << gstBufferSize << ">" << shm->mapped_size(); - return; + LOG(ERROR) << "Encoded buff too large: " + << buffer->size << ">" << shm->mapped_size(); + io_client_weak_factory_.GetWeakPtr()->NotifyError( + media::VideoEncodeAccelerator::kPlatformFailureError); + gst_buffer_unref(buffer); } - //copying data to shared memory. #if GST_VERSION_MAJOR == 1 memcpy(static_cast(shm->memory()), map.data, gstBufferSize); #else - memcpy(static_cast(shm->memory()), gst_buffer->data, gstBufferSize); + memcpy(static_cast(shm->memory()), buffer->data, gstBufferSize); #endif child_message_loop_proxy_->PostTask( @@ -226,12 +259,10 @@ GstFlowReturn TizenVideoEncodeAccelerator::Impl::OnEncoded( #else if (gst_output_buf->data) { #endif - impl->gst_thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&TizenVideoEncodeAccelerator::Impl::DeliverVideoFrame, - base::Unretained(impl), - gst_output_buf, - key_frame)); + base::AutoLock auto_lock(impl->output_queue_lock_); + impl->output_buffers_.push( + new TizenVideoEncodeAccelerator::OutputBuffer(gst_output_buf, + key_frame)); } } else { LOG(ERROR) << __FUNCTION__ << " ENCODING FRAME FAILED"; @@ -396,9 +427,8 @@ void TizenVideoEncodeAccelerator::Destroy() { gst_element_set_state(impl_->pipeline_, GST_STATE_NULL); gst_object_unref(GST_OBJECT(impl_->pipeline_)); } - - DVLOG(1) << __FUNCTION__ - << " queue size: "<< impl_->encoder_output_queue_.size(); + if (impl_->io_timer_.IsRunning()) + impl_->io_timer_.Stop(); while (!impl_->encoder_output_queue_.empty()) { media::BitstreamBuffer bitstream_buffer = impl_->encoder_output_queue_.back(); @@ -407,6 +437,11 @@ void TizenVideoEncodeAccelerator::Destroy() { new base::SharedMemory(bitstream_buffer.handle(), false)); impl_->encoder_output_queue_.pop_back(); } + while (!impl_->output_buffers_.empty()) { + OutputBuffer* output_buffer = impl_->output_buffers_.front(); + gst_buffer_unref(output_buffer->buffer_); + impl_->output_buffers_.pop(); + } delete impl_; } delete this; @@ -687,7 +722,10 @@ bool TizenVideoEncodeAccelerator::StartEncoder() { LOG(ERROR) << __FUNCTION__ << " cannot start encoder pipeline."; return false; } - + impl_->io_timer_.Start(FROM_HERE, + base::TimeDelta::FromMilliseconds(10), + impl_, + &TizenVideoEncodeAccelerator::Impl::DeliverVideoFrame); GST_DEBUG_BIN_TO_DOT_FILE( GST_BIN(gst_pipeline.get()), GST_DEBUG_GRAPH_SHOW_ALL, "encoder_graph.dot"); diff --git a/tizen_src/impl/content/common/gpu/media/tizen/tizen_video_encode_accelerator.h b/tizen_src/impl/content/common/gpu/media/tizen/tizen_video_encode_accelerator.h index 92b769a..0821880 100644 --- a/tizen_src/impl/content/common/gpu/media/tizen/tizen_video_encode_accelerator.h +++ b/tizen_src/impl/content/common/gpu/media/tizen/tizen_video_encode_accelerator.h @@ -36,6 +36,7 @@ class CONTENT_EXPORT TizenVideoEncodeAccelerator private: struct BitstreamBufferRef; struct Impl; + struct OutputBuffer; void OnEncode(scoped_ptr buffer_ref, bool force_keyframe); void OnUseOutputBitstreamBuffer(const media::BitstreamBuffer& buffer); -- 2.7.4