From 77a584be1d5af0f807e3ef14d943714d07908cae Mon Sep 17 00:00:00 2001 From: "stefan@webrtc.org" Date: Tue, 15 Jan 2013 16:34:34 +0000 Subject: [PATCH] Made ViEToFileRenderer use a separate thread for rendering frames to file. Review URL: https://webrtc-codereview.appspot.com/1021011 git-svn-id: http://webrtc.googlecode.com/svn/trunk@3373 4adac7df-926f-26a2-2b94-8c16560cd09d --- .../helpers/vie_to_file_renderer.cc | 113 ++++++++++++++++-- .../libvietest/include/vie_to_file_renderer.h | 31 ++++- 2 files changed, 129 insertions(+), 15 deletions(-) diff --git a/webrtc/video_engine/test/libvietest/helpers/vie_to_file_renderer.cc b/webrtc/video_engine/test/libvietest/helpers/vie_to_file_renderer.cc index f186aaddb4..f2b334e4f2 100644 --- a/webrtc/video_engine/test/libvietest/helpers/vie_to_file_renderer.cc +++ b/webrtc/video_engine/test/libvietest/helpers/vie_to_file_renderer.cc @@ -8,15 +8,56 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "video_engine/test/libvietest/include/vie_to_file_renderer.h" +#include "webrtc/video_engine/test/libvietest/include/vie_to_file_renderer.h" #include +#include "webrtc/system_wrappers/interface/critical_section_wrapper.h" +#include "webrtc/system_wrappers/interface/event_wrapper.h" +#include "webrtc/system_wrappers/interface/thread_wrapper.h" + +namespace test { +struct Frame { + public: + Frame(unsigned char* buffer, + int buffer_size, + uint32_t timestamp, + int64_t render_time) + : buffer(new unsigned char[buffer_size]), + buffer_size(buffer_size), + timestamp(timestamp), + render_time(render_time) { + memcpy(this->buffer.get(), buffer, buffer_size); + } + + webrtc::scoped_array buffer; + int buffer_size; + uint32_t timestamp; + int64_t render_time; + + private: + DISALLOW_COPY_AND_ASSIGN(Frame); +}; +}; // namespace test + ViEToFileRenderer::ViEToFileRenderer() - : output_file_(NULL) { + : output_file_(NULL), + output_path_(), + output_filename_(), + thread_(webrtc::ThreadWrapper::CreateThread( + ViEToFileRenderer::RunRenderThread, + this, webrtc::kNormalPriority, "ViEToFileRendererThread")), + frame_queue_cs_(webrtc::CriticalSectionWrapper::CreateCriticalSection()), + frame_render_event_(webrtc::EventWrapper::Create()), + render_queue_(), + free_frame_queue_() { } ViEToFileRenderer::~ViEToFileRenderer() { + while (!free_frame_queue_.empty()) { + delete free_frame_queue_.front(); + free_frame_queue_.pop_front(); + } } bool ViEToFileRenderer::PrepareForRendering( @@ -32,11 +73,19 @@ bool ViEToFileRenderer::PrepareForRendering( output_filename_ = output_filename; output_path_ = output_path; - return true; + unsigned int tid; + return thread_->Start(tid); } void ViEToFileRenderer::StopRendering() { assert(output_file_ != NULL); + if (thread_.get() != NULL) { + thread_->SetNotAlive(); + // Signal that a frame is ready to be written to file. + frame_render_event_->Set(); + // Call Stop() repeatedly, waiting for ProcessRenderQueue() to finish. + while (!thread_->Stop()) continue; + } std::fclose(output_file_); output_file_ = NULL; } @@ -75,16 +124,26 @@ int ViEToFileRenderer::DeliverFrame(unsigned char *buffer, int buffer_size, uint32_t time_stamp, int64_t render_time) { - assert(output_file_ != NULL); - - int written = std::fwrite(buffer, sizeof(unsigned char), - buffer_size, output_file_); - - if (written == buffer_size) { - return 0; + webrtc::CriticalSectionScoped lock(frame_queue_cs_.get()); + test::Frame* frame; + if (free_frame_queue_.empty()) { + frame = new test::Frame(buffer, buffer_size, time_stamp, render_time); } else { - return -1; + // Reuse an already allocated frame. + frame = free_frame_queue_.front(); + free_frame_queue_.pop_front(); + if (frame->buffer_size < buffer_size) { + frame->buffer.reset(new unsigned char[buffer_size]); + } + memcpy(frame->buffer.get(), buffer, buffer_size); + frame->buffer_size = buffer_size; + frame->timestamp = time_stamp; + frame->render_time = render_time; } + render_queue_.push_back(frame); + // Signal that a frame is ready to be written to file. + frame_render_event_->Set(); + return 0; } int ViEToFileRenderer::FrameSizeChange(unsigned int width, @@ -92,3 +151,35 @@ int ViEToFileRenderer::FrameSizeChange(unsigned int width, unsigned int number_of_streams) { return 0; } + +bool ViEToFileRenderer::RunRenderThread(void* obj) { + assert(obj); + ViEToFileRenderer* renderer = static_cast(obj); + return renderer->ProcessRenderQueue(); +} + +bool ViEToFileRenderer::ProcessRenderQueue() { + // Wait for a frame to be rendered. + frame_render_event_->Wait(WEBRTC_EVENT_INFINITE); + frame_queue_cs_->Enter(); + // Render all frames in the queue. + while (!render_queue_.empty()) { + test::Frame* frame = render_queue_.front(); + render_queue_.pop_front(); + // Leave the critical section before writing to file to not block calls to + // the renderer. + frame_queue_cs_->Leave(); + assert(output_file_); + int written = std::fwrite(frame->buffer.get(), sizeof(unsigned char), + frame->buffer_size, output_file_); + frame_queue_cs_->Enter(); + // Return the frame. + free_frame_queue_.push_front(frame); + if (written != frame->buffer_size) { + frame_queue_cs_->Leave(); + return false; + } + } + frame_queue_cs_->Leave(); + return true; +} diff --git a/webrtc/video_engine/test/libvietest/include/vie_to_file_renderer.h b/webrtc/video_engine/test/libvietest/include/vie_to_file_renderer.h index c272f00030..2c2f304c43 100644 --- a/webrtc/video_engine/test/libvietest/include/vie_to_file_renderer.h +++ b/webrtc/video_engine/test/libvietest/include/vie_to_file_renderer.h @@ -8,13 +8,27 @@ * be found in the AUTHORS file in the root of the source tree. */ -#ifndef SRC_VIDEO_ENGINE_TEST_AUTO_TEST_HELPERS_VIE_TO_FILE_RENDERER_H_ -#define SRC_VIDEO_ENGINE_TEST_AUTO_TEST_HELPERS_VIE_TO_FILE_RENDERER_H_ +#ifndef WEBRTC_VIDEO_ENGINE_TEST_LIBVIETEST_INCLUDE_VIE_TO_FILE_RENDERER_H_ +#define WEBRTC_VIDEO_ENGINE_TEST_LIBVIETEST_INCLUDE_VIE_TO_FILE_RENDERER_H_ #include +#include +#include #include -#include "video_engine/include/vie_render.h" +#include "webrtc/video_engine/include/vie_render.h" +#include "webrtc/system_wrappers/interface/constructor_magic.h" +#include "webrtc/system_wrappers/interface/scoped_ptr.h" + +namespace webrtc { +class CriticalSectionWrapper; +class EventWrapper; +class ThreadWrapper; +}; // namespace webrtc + +namespace test { +struct Frame; +}; // namespace test class ViEToFileRenderer: public webrtc::ExternalRenderer { public: @@ -50,11 +64,20 @@ class ViEToFileRenderer: public webrtc::ExternalRenderer { const std::string GetFullOutputPath() const; private: + typedef std::list FrameQueue; + + static bool RunRenderThread(void* obj); void ForgetOutputFile(); + bool ProcessRenderQueue(); std::FILE* output_file_; std::string output_path_; std::string output_filename_; + webrtc::scoped_ptr thread_; + webrtc::scoped_ptr frame_queue_cs_; + webrtc::scoped_ptr frame_render_event_; + FrameQueue render_queue_; + FrameQueue free_frame_queue_; }; -#endif // SRC_VIDEO_ENGINE_TEST_AUTO_TEST_HELPERS_VIE_TO_FILE_RENDERER_H_ +#endif // WEBRTC_VIDEO_ENGINE_TEST_LIBVIETEST_INCLUDE_VIE_TO_FILE_RENDERER_H_