Switching scale functions to use VideoFrame.

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@2849 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
mikhal@webrtc.org 2012-09-28 19:47:23 +00:00
parent 507146c56c
commit 2a476e9c95
6 changed files with 53 additions and 87 deletions

View File

@ -27,8 +27,6 @@ enum ScaleMethod {
kScaleBox kScaleBox
}; };
// TODO (mikhal): Have set return the expected value of the dst_frame, such
// that the user can allocate memory for Scale().
class Scaler { class Scaler {
public: public:
Scaler(); Scaler();
@ -49,9 +47,8 @@ class Scaler {
// Return value: 0 - OK, // Return value: 0 - OK,
// -1 - parameter error // -1 - parameter error
// -2 - scaler not set // -2 - scaler not set
int Scale(const uint8_t* src_frame, int Scale(const VideoFrame& src_frame,
uint8_t*& dst_frame, VideoFrame* dst_frame);
int& dst_size);
private: private:
// Determine if the VideoTypes are currently supported. // Determine if the VideoTypes are currently supported.

View File

@ -44,39 +44,33 @@ int Scaler::Set(int src_width, int src_height,
return 0; return 0;
} }
int Scaler::Scale(const uint8_t* src_frame, int Scaler::Scale(const VideoFrame& src_frame,
uint8_t*& dst_frame, VideoFrame* dst_frame) {
int& dst_size) { assert(dst_frame);
if (src_frame == NULL) if (src_frame.Buffer() == NULL || src_frame.Length() == 0)
return -1; return -1;
if (!set_) if (!set_)
return -2; return -2;
// Making sure that destination frame is of sufficient size // Making sure that destination frame is of sufficient size.
int dst_half_width = (dst_width_ + 1) >> 1; int required_dst_size = CalcBufferSize(kI420, dst_width_, dst_height_);
int dst_half_height = (dst_height_ + 1) >> 1; dst_frame->VerifyAndAllocate(required_dst_size);
int required_dst_size = dst_width_ * dst_height_ + 2 * (dst_half_width * // Set destination length and dimensions.
dst_half_height); dst_frame->SetLength(required_dst_size);
if (dst_frame && required_dst_size > dst_size) { dst_frame->SetWidth(dst_width_);
// allocated buffer is too small dst_frame->SetHeight(dst_height_);
delete [] dst_frame;
dst_frame = NULL;
}
if (dst_frame == NULL) {
// TODO(mikhal): align this buffer to 16 bytes.
dst_frame = new uint8_t[required_dst_size];
dst_size = required_dst_size;
}
int src_half_width = (src_width_ + 1) >> 1; int src_half_width = (src_width_ + 1) >> 1;
int src_half_height = (src_height_ + 1) >> 1; int src_half_height = (src_height_ + 1) >> 1;
int dst_half_width = (dst_width_ + 1) >> 1;
int dst_half_height = (dst_height_ + 1) >> 1;
// Converting to planes: // Converting to planes:
const uint8_t* src_yplane = src_frame; const uint8_t* src_yplane = src_frame.Buffer();
const uint8_t* src_uplane = src_frame + src_width_ * src_height_; const uint8_t* src_uplane = src_yplane + src_width_ * src_height_;
const uint8_t* src_vplane = src_uplane + src_half_width * src_half_height; const uint8_t* src_vplane = src_uplane + src_half_width * src_half_height;
uint8_t* dst_yplane = dst_frame; uint8_t* dst_yplane = dst_frame->Buffer();
uint8_t* dst_uplane = dst_frame + dst_width_ * dst_height_; uint8_t* dst_uplane = dst_yplane + dst_width_ * dst_height_;
uint8_t* dst_vplane = dst_uplane + dst_half_width * dst_half_height; uint8_t* dst_vplane = dst_uplane + dst_half_width * dst_half_height;
return libyuv::I420Scale(src_yplane, src_width_, return libyuv::I420Scale(src_yplane, src_width_,

View File

@ -39,7 +39,7 @@ class TestScaler : public ::testing::Test {
Scaler test_scaler_; Scaler test_scaler_;
FILE* source_file_; FILE* source_file_;
uint8_t* test_buffer_; VideoFrame test_frame_;
const int width_; const int width_;
const int height_; const int height_;
const int frame_length_; const int frame_length_;
@ -60,7 +60,8 @@ void TestScaler::SetUp() {
source_file_ = fopen(input_file_name.c_str(), "rb"); source_file_ = fopen(input_file_name.c_str(), "rb");
ASSERT_TRUE(source_file_ != NULL) << "Cannot read file: "<< ASSERT_TRUE(source_file_ != NULL) << "Cannot read file: "<<
input_file_name << "\n"; input_file_name << "\n";
test_buffer_ = new uint8_t[frame_length_]; test_frame_.VerifyAndAllocate(frame_length_);
test_frame_.SetLength(frame_length_);
} }
void TestScaler::TearDown() { void TestScaler::TearDown() {
@ -68,12 +69,11 @@ void TestScaler::TearDown() {
ASSERT_EQ(0, fclose(source_file_)); ASSERT_EQ(0, fclose(source_file_));
} }
source_file_ = NULL; source_file_ = NULL;
delete [] test_buffer_; test_frame_.Free();
} }
TEST_F(TestScaler, ScaleWithoutSettingValues) { TEST_F(TestScaler, ScaleWithoutSettingValues) {
int size = 100; EXPECT_EQ(-2, test_scaler_.Scale(test_frame_, &test_frame_));
EXPECT_EQ(-2, test_scaler_.Scale(test_buffer_, test_buffer_, size));
} }
TEST_F(TestScaler, ScaleBadInitialValues) { TEST_F(TestScaler, ScaleBadInitialValues) {
@ -85,19 +85,22 @@ TEST_F(TestScaler, ScaleBadInitialValues) {
} }
TEST_F(TestScaler, ScaleSendingNullSourcePointer) { TEST_F(TestScaler, ScaleSendingNullSourcePointer) {
int size = 0; VideoFrame null_src_frame;
EXPECT_EQ(-1, test_scaler_.Scale(NULL, test_buffer_, size)); EXPECT_EQ(-1, test_scaler_.Scale(null_src_frame, &test_frame_));
} }
TEST_F(TestScaler, ScaleSendingBufferTooSmall) { TEST_F(TestScaler, ScaleSendingBufferTooSmall) {
// Sending a buffer which is too small (should reallocate and update size) // Sending a buffer which is too small (should reallocate and update size)
EXPECT_EQ(0, test_scaler_.Set(352, 288, 144, 288, kI420, kI420, kScalePoint)); EXPECT_EQ(0, test_scaler_.Set(352, 288, 144, 288, kI420, kI420, kScalePoint));
uint8_t* test_buffer2 = NULL; VideoFrame test_frame2;
int size = 0; EXPECT_GT(fread(test_frame_.Buffer(), 1, frame_length_, source_file_), 0U);
EXPECT_GT(fread(test_buffer_, 1, frame_length_, source_file_), 0U); EXPECT_EQ(0, test_scaler_.Scale(test_frame_, &test_frame2));
EXPECT_EQ(0, test_scaler_.Scale(test_buffer_, test_buffer2, size)); EXPECT_EQ(CalcBufferSize(kI420, 144, 288),
EXPECT_EQ(144 * 288 * 3 / 2, size); static_cast<int>(test_frame2.Size()));
delete [] test_buffer2; EXPECT_EQ(144u, test_frame2.Width());
EXPECT_EQ(288u, test_frame2.Height());
EXPECT_EQ(CalcBufferSize(kI420, 144, 288),
static_cast<int>(test_frame2.Length()));
} }
//TODO (mikhal): Converge the test into one function that accepts the method. //TODO (mikhal): Converge the test into one function that accepts the method.
@ -378,9 +381,7 @@ double TestScaler::ComputeAvgSequencePSNR(FILE* input_file,
rewind(input_file); rewind(input_file);
rewind(output_file); rewind(output_file);
int half_width = (width + 1) >> 1; int required_size = CalcBufferSize(kI420, width, height);
int half_height = (height + 1) >> 1;
int required_size = height * width + 2 * (half_width * half_height);
uint8_t* input_buffer = new uint8_t[required_size]; uint8_t* input_buffer = new uint8_t[required_size];
uint8_t* output_buffer = new uint8_t[required_size]; uint8_t* output_buffer = new uint8_t[required_size];
@ -421,35 +422,30 @@ void TestScaler::ScaleSequence(ScaleMethod method,
rewind(source_file); rewind(source_file);
int src_half_width = (src_width + 1) >> 1; int out_required_size = CalcBufferSize(kI420, dst_width, dst_height);
int src_half_height = (src_height + 1) >> 1; int in_required_size = CalcBufferSize(kI420, src_width, src_height);
int dst_half_width = (dst_width + 1) >> 1;
int dst_half_height = (dst_height + 1) >> 1;
int out_required_size = dst_width * dst_height + 2 * (dst_half_width * VideoFrame input_frame, output_frame;
dst_half_height); input_frame.VerifyAndAllocate(in_required_size);
int in_required_size = src_height * src_width + 2 * (src_half_width * input_frame.SetLength(in_required_size);
src_half_height); output_frame.VerifyAndAllocate(out_required_size);
output_frame.SetLength(out_required_size);
uint8_t* input_buffer = new uint8_t[in_required_size];
uint8_t* output_buffer = new uint8_t[out_required_size];
int64_t start_clock, total_clock; int64_t start_clock, total_clock;
total_clock = 0; total_clock = 0;
int frame_count = 0; int frame_count = 0;
// Running through entire sequence // Running through entire sequence.
while (feof(source_file) == 0) { while (feof(source_file) == 0) {
if ((size_t)in_required_size != if ((size_t)in_required_size !=
fread(input_buffer, 1, in_required_size, source_file)) fread(input_frame.Buffer(), 1, in_required_size, source_file))
break; break;
start_clock = TickTime::MillisecondTimestamp(); start_clock = TickTime::MillisecondTimestamp();
EXPECT_EQ(0, test_scaler_.Scale(input_buffer, output_buffer, EXPECT_EQ(0, test_scaler_.Scale(input_frame, &output_frame));
out_required_size));
total_clock += TickTime::MillisecondTimestamp() - start_clock; total_clock += TickTime::MillisecondTimestamp() - start_clock;
if (fwrite(output_buffer, 1, out_required_size, if (fwrite(output_frame.Buffer(), 1, output_frame.Size(),
output_file) != static_cast<unsigned int>(out_required_size)) { output_file) != static_cast<unsigned int>(output_frame.Size())) {
return; return;
} }
frame_count++; frame_count++;
@ -462,8 +458,6 @@ void TestScaler::ScaleSequence(ScaleMethod method,
(static_cast<double>(total_clock) / frame_count)); (static_cast<double>(total_clock) / frame_count));
} }
ASSERT_EQ(0, fclose(output_file)); ASSERT_EQ(0, fclose(output_file));
delete [] input_buffer;
delete [] output_buffer;
} }
} // namespace webrtc } // namespace webrtc

View File

@ -35,17 +35,11 @@ int FrameScaler::ResizeFrameIfNeeded(VideoFrame* video_frame,
// Set correct scale settings and scale |video_frame| into |scaled_frame_|. // Set correct scale settings and scale |video_frame| into |scaled_frame_|.
scaler_->Set(video_frame->Width(), video_frame->Height(), out_width, scaler_->Set(video_frame->Width(), video_frame->Height(), out_width,
out_height, kI420, kI420, kScaleBox); out_height, kI420, kI420, kScaleBox);
int out_length = CalcBufferSize(kI420, out_width, out_height); int ret = scaler_->Scale(*video_frame, &scaled_frame_);
scaled_frame_.VerifyAndAllocate(out_length);
int ret = scaler_->Scale(video_frame->Buffer(), scaled_frame_.Buffer(),
out_length);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
scaled_frame_.SetWidth(out_width);
scaled_frame_.SetHeight(out_height);
scaled_frame_.SetLength(out_length);
scaled_frame_.SetRenderTime(video_frame->RenderTimeMs()); scaled_frame_.SetRenderTime(video_frame->RenderTimeMs());
scaled_frame_.SetTimeStamp(video_frame->TimeStamp()); scaled_frame_.SetTimeStamp(video_frame->TimeStamp());
video_frame->SwapFrame(scaled_frame_); video_frame->SwapFrame(scaled_frame_);

View File

@ -293,15 +293,7 @@ void VideoProcessorImpl::FrameDecoded(const VideoFrame& image) {
// upsample back to original size: needed for PSNR and SSIM computations. // upsample back to original size: needed for PSNR and SSIM computations.
if (image.Width() != config_.codec_settings->width || if (image.Width() != config_.codec_settings->width ||
image.Height() != config_.codec_settings->height) { image.Height() != config_.codec_settings->height) {
int required_size = CalcBufferSize(kI420,
config_.codec_settings->width,
config_.codec_settings->height);
VideoFrame up_image; VideoFrame up_image;
up_image.VerifyAndAllocate(required_size);
up_image.SetLength(required_size);
up_image.SetWidth(config_.codec_settings->width);
up_image.SetHeight(config_.codec_settings->height);
int ret_val = scaler_.Set(image.Width(), image.Height(), int ret_val = scaler_.Set(image.Width(), image.Height(),
config_.codec_settings->width, config_.codec_settings->width,
config_.codec_settings->height, config_.codec_settings->height,
@ -311,8 +303,7 @@ void VideoProcessorImpl::FrameDecoded(const VideoFrame& image) {
fprintf(stderr, "Failed to set scalar for frame: %d, return code: %d\n", fprintf(stderr, "Failed to set scalar for frame: %d, return code: %d\n",
frame_number, ret_val); frame_number, ret_val);
} }
ret_val = scaler_.Scale(image.Buffer(), up_image.Buffer(), ret_val = scaler_.Scale(image, &up_image);
required_size);
assert(ret_val >= 0); assert(ret_val >= 0);
if (ret_val < 0) { if (ret_val < 0) {
fprintf(stderr, "Failed to scale frame: %d, return code: %d\n", fprintf(stderr, "Failed to scale frame: %d, return code: %d\n",

View File

@ -82,16 +82,12 @@ VPMSimpleSpatialResampler::ResampleFrame(const VideoFrame& inFrame,
if (retVal < 0) if (retVal < 0)
return retVal; return retVal;
// Disabling cut/pad for now - only scaling. // Setting time parameters to the output frame - all the rest will be
int requiredSize = CalcBufferSize(kI420, _targetWidth, _targetHeight); // set by the scaler.
outFrame.VerifyAndAllocate(requiredSize);
outFrame.SetTimeStamp(inFrame.TimeStamp()); outFrame.SetTimeStamp(inFrame.TimeStamp());
outFrame.SetRenderTime(inFrame.RenderTimeMs()); outFrame.SetRenderTime(inFrame.RenderTimeMs());
outFrame.SetWidth(_targetWidth);
outFrame.SetHeight(_targetHeight);
retVal = _scaler.Scale(inFrame.Buffer(), outFrame.Buffer(), requiredSize); retVal = _scaler.Scale(inFrame, &outFrame);
outFrame.SetLength(requiredSize);
if (retVal == 0) if (retVal == 0)
return VPM_OK; return VPM_OK;
else else