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
This commit is contained in:
stefan@webrtc.org 2013-01-15 16:34:34 +00:00
parent a22a9bd9ca
commit 77a584be1d
2 changed files with 129 additions and 15 deletions

View File

@ -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 <assert.h>
#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<unsigned char> 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<ViEToFileRenderer*>(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;
}

View File

@ -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 <cstdio>
#include <cstring>
#include <list>
#include <string>
#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<test::Frame*> 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<webrtc::ThreadWrapper> thread_;
webrtc::scoped_ptr<webrtc::CriticalSectionWrapper> frame_queue_cs_;
webrtc::scoped_ptr<webrtc::EventWrapper> 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_