diff --git a/src/test/test.gyp b/src/test/test.gyp index 99e9239317..75f8df2ad3 100644 --- a/src/test/test.gyp +++ b/src/test/test.gyp @@ -75,5 +75,19 @@ 'testsupport/packet_reader_unittest.cc', ], }, + { + 'target_name': 'rgba_to_i420_converter', + 'type': 'executable', + 'dependencies': [ + 'test_support', + '<(webrtc_root)/../third_party/google-gflags/google-gflags.gyp:google-gflags', + '<(webrtc_root)/../third_party/libyuv/libyuv.gyp:libyuv', + ], + 'sources': [ + 'testsupport/converter/converter.h', + 'testsupport/converter/converter.cc', + 'testsupport/converter/rgba_to_i420_converter.cc', + ], + }, ], } diff --git a/src/test/testsupport/converter/converter.cc b/src/test/testsupport/converter/converter.cc new file mode 100644 index 0000000000..70b7ea8036 --- /dev/null +++ b/src/test/testsupport/converter/converter.cc @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2012 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 +#include + +#include +#include + +#include "testsupport/converter/converter.h" +#include "testsupport/frame_reader.h" + +#ifdef WIN32 +#define SEPARATOR '\\' +#define STAT _stat +#else +#define SEPARATOR '/' +#define STAT stat +#endif + +namespace webrtc { +namespace test { + +Converter::Converter(int width, int height) + : width_(width), + height_(height) { +} + +bool Converter::ConvertRGBAToI420Video(std::string frames_dir, + std::string output_file_name) { + FILE* output_file = fopen(output_file_name.c_str(), "ab"); + + // Open output file in append mode. + if (output_file == NULL) { + fprintf(stderr, "Couldn't open input file for reading: %s\n", + output_file_name.c_str()); + return false; + } + + int input_frame_size = InputFrameSize(); + uint8* rgba_buffer = new uint8[input_frame_size]; + int y_plane_size = YPlaneSize(); + uint8* dst_y = new uint8[y_plane_size]; + int u_plane_size = UPlaneSize(); + uint8* dst_u = new uint8[u_plane_size]; + int v_plane_size = VPlaneSize(); + uint8* dst_v = new uint8[v_plane_size]; + + int counter = 0; // Counter to form frame names. + bool success = false; // Is conversion successful. + + while (true) { + std::string file_name = FormFrameName(4, counter); + // Get full path file name. + std::string input_file_name = FindFullFileName(frames_dir, file_name); + + if (FileExists(input_file_name)) { + ++counter; // Update counter for the next round. + } else { + fprintf(stdout, "Reached end of frames list\n"); + break; + } + + // Read the RGBA frame into rgba_buffer. + ReadRGBAFrame(input_file_name.c_str(), input_frame_size, rgba_buffer); + + // Convert to I420 frame. + libyuv::ABGRToI420(rgba_buffer, SrcStrideFrame(), + dst_y, DstStrideY(), + dst_u, DstStrideU(), + dst_v, DstStrideV(), + width_, height_); + + // Add the I420 frame to the YUV video file. + success = AddYUVToFile(dst_y, y_plane_size, dst_u, u_plane_size, + dst_v, v_plane_size, output_file); + + + if (!success) { + fprintf(stderr, "LibYUV error during RGBA to I420 frame conversion\n"); + break; + } + } + + delete[] rgba_buffer; + delete[] dst_y; + delete[] dst_u; + delete[] dst_v; + + fclose(output_file); + + return success; +} + +bool Converter::AddYUVToFile(uint8* y_plane, int y_plane_size, + uint8* u_plane, int u_plane_size, + uint8* v_plane, int v_plane_size, + FILE* output_file) { + bool success = AddYUVPlaneToFile(y_plane, y_plane_size, output_file) && + AddYUVPlaneToFile(u_plane, u_plane_size, output_file) && + AddYUVPlaneToFile(v_plane, v_plane_size, output_file); + return success; +} + +bool Converter::AddYUVPlaneToFile(uint8* yuv_plane, int yuv_plane_size, + FILE* file) { + size_t bytes_written = fwrite(yuv_plane, 1, yuv_plane_size, file); + + if (bytes_written != static_cast(yuv_plane_size)) { + fprintf(stderr, "Number of bytes written (%d) doesn't match size of y plane" + " (%d)\n", static_cast(bytes_written), yuv_plane_size); + return false; + } + return true; +} + +bool Converter::ReadRGBAFrame(const char* input_file_name, int input_frame_size, + unsigned char* buffer) { + // Use FrameReader. + FrameReaderImpl frame_reader(input_file_name, input_frame_size); + if (!frame_reader.Init()) { + fprintf(stderr, "Couldn't initialize FrameReader for frame %s", + input_file_name); + return false; + } + frame_reader.ReadFrame(buffer); + return true; +} + +std::string Converter::FindFullFileName(std::string dir_name, + std::string file_name) { + return dir_name + SEPARATOR + file_name; +} + +bool Converter:: FileExists(std::string file_name_to_check) { + struct STAT file_info; + int result = STAT(file_name_to_check.c_str(), &file_info); + return (result == 0); +} + +std::string Converter::FormFrameName(int width, int number) { + std::stringstream tmp; + + // Zero-pad number to a string. + tmp << std::setfill('0') << std::setw(width) << number; + + return "frame_" + tmp.str(); +} + +} // namespace test +} // namespace webrtc + + diff --git a/src/test/testsupport/converter/converter.h b/src/test/testsupport/converter/converter.h new file mode 100644 index 0000000000..a03fd44598 --- /dev/null +++ b/src/test/testsupport/converter/converter.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2012 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_SRC_TEST_TESTSUPPORT_CONVERTER_CONVERTER_H_ +#define WEBRTC_SRC_TEST_TESTSUPPORT_CONVERTER_CONVERTER_H_ + +#include + +#include "third_party/libyuv/include/libyuv.h" + +namespace webrtc { +namespace test { + +// Handles a conversion between a set of RGBA frames to a YUV (I420) video. +class Converter { + public: + Converter(int width, int height); + + // Converts RGBA to YUV video. + bool ConvertRGBAToI420Video(std::string frames_dir, + std::string output_file_name); + + private: + int width_; // Width of the video (respectively of the RGBA frames). + int height_; // Height of the video (respectively of the RGBA frames). + + // Returns the size of the Y plane in bytes. + int YPlaneSize() const { + return width_*height_; + } + + // Returns the size of the U plane in bytes. + int UPlaneSize() const { + return ((width_+1)/2)*((height_)/2); + } + + // Returns the size of the V plane in bytes. + int VPlaneSize() const { + return ((width_+1)/2)*((height_)/2); + } + + // Returns the number of bytes per row in the RGBA frame. + int SrcStrideFrame() const { + return width_*4; + } + + // Returns the number of bytes in the Y plane. + int DstStrideY() const { + return width_; + } + + // Returns the number of bytes in the U plane. + int DstStrideU() const { + return (width_+1)/2; + } + + // Returns the number of bytes in the V plane. + int DstStrideV() const { + return (width_+1)/2; + } + + // Returns the size in bytes of the input RGBA frames. + int InputFrameSize() const { + return width_*height_*4; + } + + // Writes the Y, U and V (in this order) planes to the file, thus adding a + // raw YUV frame to the file. + bool AddYUVToFile(uint8* y_plane, int y_plane_size, + uint8* u_plane, int u_plane_size, + uint8* v_plane, int v_plane_size, + FILE* output_file); + + // Adds the Y, U or V plane to the file. + bool AddYUVPlaneToFile(uint8* yuv_plane, int yuv_plane_size, FILE* file); + + // Reads a RGBA frame from input_file_name with input_frame_size size in bytes + // into the buffer. + bool ReadRGBAFrame(const char* input_file_name, int input_frame_size, + unsigned char* buffer); + + // Finds the full path name of the file - concatenates the directory and file + // names. + std::string FindFullFileName(std::string dir_name, std::string file_name); + + // Checks if a file exists. + bool FileExists(std::string file_name_to_check); + + // Returns the name of the file in the form frame_, where is + // 4 zero padded (i.e. frame_0000, frame_0001, etc.). + std::string FormFrameName(int width, int number); +}; + +} // namespace test +} // namespace webrtc + +#endif // WEBRTC_SRC_TEST_TESTSUPPORT_CONVERTER_CONVERTER_H_ diff --git a/src/test/testsupport/converter/rgba_to_i420_converter.cc b/src/test/testsupport/converter/rgba_to_i420_converter.cc new file mode 100644 index 0000000000..8bce66c369 --- /dev/null +++ b/src/test/testsupport/converter/rgba_to_i420_converter.cc @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2012 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 + +#include "google/gflags.h" +#include "testsupport/converter/converter.h" + +DEFINE_int32(width, -1, "Width in pixels of the frames in the input file."); +DEFINE_int32(height, -1, "Height in pixels of the frames in the input file."); +DEFINE_string(frames_dir, ".", "The path to the directory where the frames " + "reside"); +DEFINE_string(output_file, "./output.yuv", "The output file to which frames are" + " written"); + +/* + * A command-line tool based on libyuv to convert a set of RGBA files to a YUV + * video. + * Usage: + * rgba_to_i420_converter --frames_dir= + * --output_file= --width= + * --height= + * + * should be an empty file because we open it in append mode + */ +int main(int argc, char** argv) { + std::string program_name = argv[0]; + std::string usage = "Converts RGBA raw image files to I420 frames for YUV.\n" + "Run " + program_name + " --helpshort for usage.\n" + "Example usage:\n" + program_name + + " --frames_dir=. --output_file=output.yuv --width=320 --height=240\n"; + google::SetUsageMessage(usage); + + google::ParseCommandLineFlags(&argc, &argv, true); + + fprintf(stdout, "You entered the following flags: frames_dir=%s, " + "output_file=%s, width=%d, height=%d\n", FLAGS_frames_dir.c_str(), + FLAGS_output_file.c_str(), FLAGS_width, FLAGS_height); + + webrtc::test::Converter converter(FLAGS_width, FLAGS_height); + bool success = converter.ConvertRGBAToI420Video(FLAGS_frames_dir, + FLAGS_output_file); + + if (success) { + fprintf(stdout, "Successful conversion of RGBA frames to YUV video!\n"); + return 0; + } else { + fprintf(stdout, "Unsuccessful conversion of RGBA frames to YUV video!\n"); + return -1; + } +} +