blob: ca5eb26703ea522e34b7d42ccc5f8515fe20893b [file] [log] [blame]
/*
* 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 "rtc_tools/converter/converter.h"
#include <stdio.h>
#include <sys/stat.h>
#include <iomanip>
#include <sstream>
#include "third_party/libyuv/include/libyuv/compare.h"
#include "third_party/libyuv/include/libyuv/convert.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,
bool delete_frames) {
FILE* output_file = fopen(output_file_name.c_str(), "wb");
// 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_t* rgba_buffer = new uint8_t[input_frame_size];
int y_plane_size = YPlaneSize();
uint8_t* dst_y = new uint8_t[y_plane_size];
int u_plane_size = UPlaneSize();
uint8_t* dst_u = new uint8_t[u_plane_size];
int v_plane_size = VPlaneSize();
uint8_t* dst_v = new uint8_t[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);
// Delete the input frame.
if (delete_frames) {
if (remove(input_file_name.c_str()) != 0) {
fprintf(stderr, "Cannot delete file %s\n", input_file_name.c_str());
}
}
// 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_t* y_plane,
int y_plane_size,
uint8_t* u_plane,
int u_plane_size,
uint8_t* 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_t* 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<size_t>(yuv_plane_size)) {
fprintf(stderr,
"Number of bytes written (%d) doesn't match size of y plane"
" (%d)\n",
static_cast<int>(bytes_written), yuv_plane_size);
return false;
}
return true;
}
bool Converter::ReadRGBAFrame(const char* input_file_name,
int input_frame_size,
unsigned char* buffer) {
FILE* input_file = fopen(input_file_name, "rb");
if (input_file == NULL) {
fprintf(stderr, "Couldn't open input file for reading: %s\n",
input_file_name);
return false;
}
size_t nbr_read = fread(buffer, 1, input_frame_size, input_file);
fclose(input_file);
if (nbr_read != static_cast<size_t>(input_frame_size)) {
fprintf(stderr, "Error reading from input file: %s\n", input_file_name);
return false;
}
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