Refactor frame generation code so it can be used by multiple modules.

R=pbos@webrtc.org, stefan@webrtc.org, pbos, stefan
BUG=

Review URL: https://webrtc-codereview.appspot.com/2240004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@4791 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
andresp@webrtc.org 2013-09-19 12:14:03 +00:00
parent 7a30dfdc69
commit ab6549562b
15 changed files with 232 additions and 318 deletions

View File

@ -52,6 +52,17 @@
'conditions': [
['include_tests==1', {
'targets': [
{
'target_name': 'frame_generator',
'type': 'static_library',
'sources': [
'test/frame_generator.h',
'test/frame_generator.cc',
],
'dependencies': [
'common_video',
],
},
{
'target_name': 'common_video_unittests',
'type': '<(gtest_target_type)',

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/common_video/test/frame_generator.h"
#include <stdio.h>
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
namespace webrtc {
namespace test {
namespace {
class YuvFileGenerator : public FrameGenerator {
public:
YuvFileGenerator(FILE* file, size_t width, size_t height)
: file_(file), width_(width), height_(height) {
assert(file);
assert(width > 0);
assert(height > 0);
frame_size_ = CalcBufferSize(
kI420, static_cast<int>(width_), static_cast<int>(height_));
frame_buffer_ = new uint8_t[frame_size_];
frame_.CreateEmptyFrame(static_cast<int>(width),
static_cast<int>(height),
static_cast<int>(width),
static_cast<int>((width + 1) / 2),
static_cast<int>((width + 1) / 2));
}
virtual ~YuvFileGenerator() {
fclose(file_);
delete[] frame_buffer_;
}
virtual I420VideoFrame& NextFrame() OVERRIDE {
size_t count = fread(frame_buffer_, 1, frame_size_, file_);
if (count < frame_size_) {
rewind(file_);
return NextFrame();
}
ConvertToI420(kI420,
frame_buffer_,
0,
0,
static_cast<int>(width_),
static_cast<int>(height_),
0,
kRotateNone,
&frame_);
return frame_;
}
private:
FILE* file_;
size_t width_;
size_t height_;
size_t frame_size_;
uint8_t* frame_buffer_;
I420VideoFrame frame_;
};
} // namespace
FrameGenerator* FrameGenerator::CreateFromYuvFile(const char* file,
size_t width,
size_t height) {
FILE* file_handle = fopen(file, "r");
assert(file_handle);
return new YuvFileGenerator(file_handle, width, height);
}
} // namespace test
} // namespace webrtc

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_COMMON_VIDEO_TEST_FRAME_GENERATOR_H_
#define WEBRTC_COMMON_VIDEO_TEST_FRAME_GENERATOR_H_
#include "webrtc/common_video/interface/i420_video_frame.h"
#include "webrtc/typedefs.h"
namespace webrtc {
namespace test {
class FrameGenerator {
public:
FrameGenerator() {}
virtual ~FrameGenerator() {}
// Returns video frame that remains valid until next call.
virtual I420VideoFrame& NextFrame() = 0;
static FrameGenerator* CreateFromYuvFile(const char* file,
size_t width,
size_t height);
};
} // namespace test
} // namespace webrtc
#endif // WEBRTC_COMMON_VIDEO_TEST_FRAME_GENERATOR_H_

View File

@ -1,64 +0,0 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/video_engine/test/common/file_capturer.h"
#include <stdio.h>
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
namespace webrtc {
namespace test {
YuvFileFrameGenerator* YuvFileFrameGenerator::Create(const char* file,
size_t width,
size_t height,
Clock* clock) {
FILE* file_handle = fopen(file, "r");
if (file_handle == NULL) {
return NULL;
}
return new YuvFileFrameGenerator(file_handle, width, height, clock);
}
YuvFileFrameGenerator::YuvFileFrameGenerator(FILE* file,
size_t width,
size_t height,
Clock* clock)
: FrameGenerator(width, height, clock), file_(file) {
frame_size_ = CalcBufferSize(
kI420, static_cast<int>(width_), static_cast<int>(height_));
frame_buffer_ = new uint8_t[frame_size_];
}
YuvFileFrameGenerator::~YuvFileFrameGenerator() {
fclose(file_);
delete[] frame_buffer_;
}
void YuvFileFrameGenerator::GenerateNextFrame() {
size_t count = fread(frame_buffer_, 1, frame_size_, file_);
if (count < frame_size_) {
rewind(file_);
return;
}
ConvertToI420(kI420,
frame_buffer_,
0,
0,
static_cast<int>(width_),
static_cast<int>(height_),
0,
kRotateNone,
&frame_);
}
} // namespace test
} // namespace webrtc

View File

@ -1,46 +0,0 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_VIDEO_ENGINE_TEST_COMMON_FILE_CAPTURER_H_
#define WEBRTC_VIDEO_ENGINE_TEST_COMMON_FILE_CAPTURER_H_
#include <stdio.h>
#include "webrtc/typedefs.h"
#include "webrtc/video_engine/test/common/frame_generator.h"
#include "webrtc/video_engine/test/common/video_capturer.h"
namespace webrtc {
class Clock;
class VideoSendStreamInput;
namespace test {
class YuvFileFrameGenerator : public FrameGenerator {
public:
static YuvFileFrameGenerator* Create(const char* file_name,
size_t width,
size_t height,
Clock* clock);
virtual ~YuvFileFrameGenerator();
private:
YuvFileFrameGenerator(FILE* file, size_t width, size_t height, Clock* clock);
virtual void GenerateNextFrame() OVERRIDE;
FILE* file_;
size_t frame_size_;
uint8_t* frame_buffer_;
};
} // namespace test
} // namespace webrtc
#endif // WEBRTC_VIDEO_ENGINE_TEST_COMMON_VIDEO_CAPTURER_H_

View File

@ -1,88 +0,0 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/video_engine/test/common/frame_generator.h"
#include <math.h>
#include <string.h>
#include "webrtc/system_wrappers/interface/clock.h"
#include "webrtc/video_engine/new_include/video_send_stream.h"
namespace webrtc {
namespace test {
FrameGenerator* FrameGenerator::Create(size_t width,
size_t height,
Clock* clock) {
return new ChromaFrameGenerator(width, height, clock);
}
void FrameGenerator::InsertFrame(VideoSendStreamInput* input) {
int64_t time_before = clock_->CurrentNtpInMilliseconds();
frame_.set_render_time_ms(time_before);
GenerateNextFrame();
int64_t time_after = clock_->CurrentNtpInMilliseconds();
input->PutFrame(frame_, static_cast<uint32_t>(time_after - time_before));
}
FrameGenerator::FrameGenerator(size_t width, size_t height, Clock* clock)
: width_(width), height_(height), clock_(clock) {
// Generate frame by constructor arguments
assert(width > 0);
assert(height > 0);
frame_.CreateEmptyFrame(static_cast<int>(width),
static_cast<int>(height),
static_cast<int>(width),
static_cast<int>((width + 1) / 2),
static_cast<int>((width + 1) / 2));
}
BlackFrameGenerator::BlackFrameGenerator(size_t width,
size_t height,
Clock* clock)
: FrameGenerator(width, height, clock) {
memset(frame_.buffer(kYPlane), 0x00, frame_.allocated_size(kYPlane));
memset(frame_.buffer(kUPlane), 0x80, frame_.allocated_size(kUPlane));
memset(frame_.buffer(kVPlane), 0x80, frame_.allocated_size(kVPlane));
}
void BlackFrameGenerator::GenerateNextFrame() {}
WhiteFrameGenerator::WhiteFrameGenerator(size_t width,
size_t height,
Clock* clock)
: FrameGenerator(width, height, clock) {
memset(frame_.buffer(kYPlane), 0xFF, frame_.allocated_size(kYPlane));
memset(frame_.buffer(kUPlane), 0x80, frame_.allocated_size(kUPlane));
memset(frame_.buffer(kVPlane), 0x80, frame_.allocated_size(kVPlane));
}
void WhiteFrameGenerator::GenerateNextFrame() {}
ChromaFrameGenerator::ChromaFrameGenerator(size_t width,
size_t height,
Clock* clock)
: FrameGenerator(width, height, clock) {
memset(frame_.buffer(kYPlane), 0x80, frame_.allocated_size(kYPlane));
}
void ChromaFrameGenerator::GenerateNextFrame() {
double angle = static_cast<double>(frame_.render_time_ms()) / 1000.0;
uint8_t u = fabs(sin(angle)) * 0xFF;
uint8_t v = fabs(cos(angle)) * 0xFF;
memset(frame_.buffer(kUPlane), u, frame_.allocated_size(kUPlane));
memset(frame_.buffer(kVPlane), v, frame_.allocated_size(kVPlane));
}
} // test
} // webrtc

View File

@ -1,68 +0,0 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_VIDEO_ENGINE_TEST_COMMON_FRAME_GENERATOR_H_
#define WEBRTC_VIDEO_ENGINE_TEST_COMMON_FRAME_GENERATOR_H_
#include "webrtc/common_video/interface/i420_video_frame.h"
#include "webrtc/typedefs.h"
namespace webrtc {
class Clock;
class VideoSendStreamInput;
namespace test {
// A set of classes that generate sequences of I420VideoFrames for testing
// without using the webcam.
class FrameGenerator {
public:
static FrameGenerator* Create(size_t width, size_t height, Clock* clock);
virtual ~FrameGenerator() {}
void InsertFrame(VideoSendStreamInput* input);
protected:
FrameGenerator(size_t width, size_t height, Clock* clock);
virtual void GenerateNextFrame() = 0;
size_t width_, height_;
I420VideoFrame frame_;
Clock* clock_;
};
class BlackFrameGenerator : public FrameGenerator {
public:
BlackFrameGenerator(size_t width, size_t height, Clock* clock);
private:
virtual void GenerateNextFrame() OVERRIDE;
};
class WhiteFrameGenerator : public FrameGenerator {
public:
WhiteFrameGenerator(size_t width, size_t height, Clock* clock);
private:
virtual void GenerateNextFrame() OVERRIDE;
};
class ChromaFrameGenerator : public FrameGenerator {
public:
ChromaFrameGenerator(size_t width, size_t height, Clock* clock);
private:
virtual void GenerateNextFrame() OVERRIDE;
};
} // test
} // webrtc
#endif // WEBRTC_VIDEO_ENGINE_TEST_COMMON_FRAME_GENERATOR_H_

View File

@ -10,22 +10,58 @@
#include "webrtc/video_engine/test/common/frame_generator_capturer.h"
#include <math.h>
#include <string.h>
#include "webrtc/common_video/test/frame_generator.h"
#include "webrtc/system_wrappers/interface/clock.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/event_wrapper.h"
#include "webrtc/system_wrappers/interface/sleep.h"
#include "webrtc/system_wrappers/interface/thread_wrapper.h"
#include "webrtc/video_engine/test/common/frame_generator.h"
#include "webrtc/video_engine/new_include/video_send_stream.h"
namespace webrtc {
namespace test {
namespace {
class ChromaGenerator : public FrameGenerator {
public:
ChromaGenerator(size_t width, size_t height, Clock* clock) : clock_(clock) {
assert(width > 0);
assert(height > 0);
frame_.CreateEmptyFrame(static_cast<int>(width),
static_cast<int>(height),
static_cast<int>(width),
static_cast<int>((width + 1) / 2),
static_cast<int>((width + 1) / 2));
memset(frame_.buffer(kYPlane), 0x80, frame_.allocated_size(kYPlane));
}
virtual I420VideoFrame& NextFrame() OVERRIDE {
double angle =
static_cast<double>(clock_->CurrentNtpInMilliseconds()) / 1000.0;
uint8_t u = fabs(sin(angle)) * 0xFF;
uint8_t v = fabs(cos(angle)) * 0xFF;
memset(frame_.buffer(kUPlane), u, frame_.allocated_size(kUPlane));
memset(frame_.buffer(kVPlane), v, frame_.allocated_size(kVPlane));
return frame_;
}
private:
Clock* clock_;
I420VideoFrame frame_;
};
} // namespace
FrameGeneratorCapturer* FrameGeneratorCapturer::Create(
VideoSendStreamInput* input,
FrameGenerator* frame_generator,
int target_fps) {
FrameGeneratorCapturer* capturer =
new FrameGeneratorCapturer(input, frame_generator, target_fps);
size_t width,
size_t height,
int target_fps,
Clock* clock) {
FrameGeneratorCapturer* capturer = new FrameGeneratorCapturer(
clock, input, new ChromaGenerator(width, height, clock), target_fps);
if (!capturer->Init()) {
delete capturer;
return NULL;
@ -34,11 +70,32 @@ FrameGeneratorCapturer* FrameGeneratorCapturer::Create(
return capturer;
}
FrameGeneratorCapturer::FrameGeneratorCapturer(
FrameGeneratorCapturer* FrameGeneratorCapturer::CreateFromYuvFile(
VideoSendStreamInput* input,
FrameGenerator* frame_generator,
int target_fps)
const char* file_name,
size_t width,
size_t height,
int target_fps,
Clock* clock) {
FrameGeneratorCapturer* capturer = new FrameGeneratorCapturer(
clock,
input,
FrameGenerator::CreateFromYuvFile(file_name, width, height),
target_fps);
if (!capturer->Init()) {
delete capturer;
return NULL;
}
return capturer;
}
FrameGeneratorCapturer::FrameGeneratorCapturer(Clock* clock,
VideoSendStreamInput* input,
FrameGenerator* frame_generator,
int target_fps)
: VideoCapturer(input),
clock_(clock),
sending_(false),
tick_(EventWrapper::Create()),
lock_(CriticalSectionWrapper::CreateCriticalSection()),
@ -82,8 +139,13 @@ bool FrameGeneratorCapturer::Run(void* obj) {
void FrameGeneratorCapturer::InsertFrame() {
{
CriticalSectionScoped cs(lock_.get());
if (sending_)
frame_generator_->InsertFrame(input_);
if (sending_) {
int64_t time_before = clock_->CurrentNtpInMilliseconds();
I420VideoFrame& frame = frame_generator_->NextFrame();
frame.set_render_time_ms(time_before);
int64_t time_after = clock_->CurrentNtpInMilliseconds();
input_->PutFrame(frame, static_cast<uint32_t>(time_after - time_before));
}
}
tick_->Wait(WEBRTC_EVENT_INFINITE);
}

View File

@ -26,24 +26,33 @@ class FrameGenerator;
class FrameGeneratorCapturer : public VideoCapturer {
public:
// The FrameGeneratorCapturer takes ownership of the FrameGenerator, which
// will be freed when the FrameGeneratorCapturer is deleted.
static FrameGeneratorCapturer* Create(VideoSendStreamInput* input,
FrameGenerator* frame_generator,
int target_fps);
size_t width,
size_t height,
int target_fps,
Clock* clock);
static FrameGeneratorCapturer* CreateFromYuvFile(VideoSendStreamInput* input,
const char* file_name,
size_t width,
size_t height,
int target_fps,
Clock* clock);
virtual ~FrameGeneratorCapturer();
virtual void Start() OVERRIDE;
virtual void Stop() OVERRIDE;
private:
FrameGeneratorCapturer(VideoSendStreamInput* input,
FrameGeneratorCapturer(Clock* clock,
VideoSendStreamInput* input,
FrameGenerator* frame_generator,
int target_fps);
bool Init();
void InsertFrame();
static bool Run(void* obj);
Clock* clock_;
bool sending_;
scoped_ptr<EventWrapper> tick_;

View File

@ -11,8 +11,6 @@
#include "webrtc/video_engine/test/common/video_capturer.h"
#include "webrtc/test/testsupport/fileutils.h"
#include "webrtc/video_engine/test/common/file_capturer.h"
#include "webrtc/video_engine/test/common/frame_generator.h"
#include "webrtc/video_engine/test/common/frame_generator_capturer.h"
#include "webrtc/video_engine/test/common/vcm_capturer.h"
@ -44,8 +42,7 @@ VideoCapturer* VideoCapturer::Create(VideoSendStreamInput* input,
// TODO(pbos): Log a warning that this failed.
FrameGeneratorCapturer* frame_generator_capturer =
FrameGeneratorCapturer::Create(
input, FrameGenerator::Create(width, height, clock), fps);
FrameGeneratorCapturer::Create(input, width, height, fps, clock);
if (frame_generator_capturer != NULL) {
return frame_generator_capturer;
}

View File

@ -22,7 +22,6 @@
#include "webrtc/video_engine/test/common/direct_transport.h"
#include "webrtc/video_engine/test/common/fake_decoder.h"
#include "webrtc/video_engine/test/common/fake_encoder.h"
#include "webrtc/video_engine/test/common/frame_generator.h"
#include "webrtc/video_engine/test/common/frame_generator_capturer.h"
#include "webrtc/video_engine/test/common/generate_ssrcs.h"
#include "webrtc/video_engine/test/common/rtp_rtcp_observer.h"
@ -84,12 +83,12 @@ class EngineTest : public ::testing::TestWithParam<EngineTestParams> {
}
void CreateFrameGenerator() {
frame_generator_capturer_.reset(test::FrameGeneratorCapturer::Create(
send_stream_->Input(),
test::FrameGenerator::Create(send_config_.codec.width,
send_config_.codec.height,
Clock::GetRealTimeClock()),
30));
frame_generator_capturer_.reset(
test::FrameGeneratorCapturer::Create(send_stream_->Input(),
send_config_.codec.width,
send_config_.codec.height,
30,
Clock::GetRealTimeClock()));
}
void StartSending() {

View File

@ -25,7 +25,6 @@
#include "webrtc/typedefs.h"
#include "webrtc/video_engine/new_include/call.h"
#include "webrtc/video_engine/test/common/direct_transport.h"
#include "webrtc/video_engine/test/common/file_capturer.h"
#include "webrtc/video_engine/test/common/frame_generator_capturer.h"
#include "webrtc/video_engine/test/common/generate_ssrcs.h"
#include "webrtc/video_engine/test/common/statistics.h"
@ -304,17 +303,14 @@ TEST_P(FullStackTest, DISABLED_NoPacketLoss) {
VideoSendStream* send_stream = call->CreateSendStream(send_config);
analyzer.input_ = send_stream->Input();
Clock* test_clock = Clock::GetRealTimeClock();
scoped_ptr<test::FrameGeneratorCapturer> file_capturer(
test::FrameGeneratorCapturer::Create(
test::FrameGeneratorCapturer::CreateFromYuvFile(
&analyzer,
test::YuvFileFrameGenerator::Create(
test::ResourcePath(params.clip.name, "yuv").c_str(),
params.clip.width,
params.clip.height,
test_clock),
params.clip.fps));
test::ResourcePath(params.clip.name, "yuv").c_str(),
params.clip.width,
params.clip.height,
params.clip.fps,
Clock::GetRealTimeClock()));
VideoReceiveStream::Config receive_config = call->GetDefaultReceiveConfig();
receive_config.rtp.ssrc = send_config.rtp.ssrcs[0];

View File

@ -25,7 +25,6 @@
#include "webrtc/video_engine/test/common/direct_transport.h"
#include "webrtc/video_engine/test/common/fake_decoder.h"
#include "webrtc/video_engine/test/common/fake_encoder.h"
#include "webrtc/video_engine/test/common/frame_generator.h"
#include "webrtc/video_engine/test/common/frame_generator_capturer.h"
#include "webrtc/video_engine/test/common/generate_ssrcs.h"
@ -168,12 +167,11 @@ TEST_P(RampUpTest, RampUpWithPadding) {
call->CreateReceiveStream(receive_config);
scoped_ptr<test::FrameGeneratorCapturer> frame_generator_capturer(
test::FrameGeneratorCapturer::Create(
send_stream->Input(),
test::FrameGenerator::Create(send_config.codec.width,
send_config.codec.height,
Clock::GetRealTimeClock()),
30));
test::FrameGeneratorCapturer::Create(send_stream->Input(),
send_config.codec.width,
send_config.codec.height,
30,
Clock::GetRealTimeClock()));
receive_stream->StartReceive();
send_stream->StartSend();

View File

@ -16,7 +16,6 @@
#include "webrtc/system_wrappers/interface/sleep.h"
#include "webrtc/system_wrappers/interface/thread_wrapper.h"
#include "webrtc/video_engine/test/common/fake_encoder.h"
#include "webrtc/video_engine/test/common/frame_generator.h"
#include "webrtc/video_engine/test/common/frame_generator_capturer.h"
#include "webrtc/video_engine/test/common/null_transport.h"
#include "webrtc/video_engine/new_include/call.h"
@ -54,9 +53,7 @@ class VideoSendStreamTest : public ::testing::Test {
VideoSendStream* send_stream = call->CreateSendStream(config);
scoped_ptr<test::FrameGeneratorCapturer> frame_generator_capturer(
test::FrameGeneratorCapturer::Create(
send_stream->Input(),
test::FrameGenerator::Create(320, 240, Clock::GetRealTimeClock()),
30));
send_stream->Input(), 320, 240, 30, Clock::GetRealTimeClock()));
send_stream->StartSend();
frame_generator_capturer->Start();

View File

@ -18,12 +18,8 @@
'common/fake_decoder.h',
'common/fake_encoder.cc',
'common/fake_encoder.h',
'common/file_capturer.cc',
'common/file_capturer.h',
'common/flags.cc',
'common/flags.h',
'common/frame_generator.cc',
'common/frame_generator.h',
'common/frame_generator_capturer.cc',
'common/frame_generator_capturer.h',
'common/generate_ssrcs.cc',
@ -119,6 +115,7 @@
'<(webrtc_root)/modules/modules.gyp:video_capture_module',
'<(webrtc_root)/test/test.gyp:test_support',
'video_engine_core',
'<(webrtc_root)/common_video/common_video.gyp:frame_generator',
],
},
{