1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10 #include "rtc_tools/converter/converter.h"
11
12 #include <stdio.h>
13 #include <sys/stat.h>
14
15 #include <iomanip>
16 #include <sstream>
17
18 #include "third_party/libyuv/include/libyuv/compare.h"
19 #include "third_party/libyuv/include/libyuv/convert.h"
20
21 #ifdef WIN32
22 #define SEPARATOR '\\'
23 #define STAT _stat
24 #else
25 #define SEPARATOR '/'
26 #define STAT stat
27 #endif
28
29 namespace webrtc {
30 namespace test {
31
Converter(int width,int height)32 Converter::Converter(int width, int height) : width_(width), height_(height) {}
33
ConvertRGBAToI420Video(std::string frames_dir,std::string output_file_name,bool delete_frames)34 bool Converter::ConvertRGBAToI420Video(std::string frames_dir,
35 std::string output_file_name,
36 bool delete_frames) {
37 FILE* output_file = fopen(output_file_name.c_str(), "wb");
38
39 // Open output file in append mode.
40 if (output_file == NULL) {
41 fprintf(stderr, "Couldn't open input file for reading: %s\n",
42 output_file_name.c_str());
43 return false;
44 }
45
46 int input_frame_size = InputFrameSize();
47 uint8_t* rgba_buffer = new uint8_t[input_frame_size];
48 int y_plane_size = YPlaneSize();
49 uint8_t* dst_y = new uint8_t[y_plane_size];
50 int u_plane_size = UPlaneSize();
51 uint8_t* dst_u = new uint8_t[u_plane_size];
52 int v_plane_size = VPlaneSize();
53 uint8_t* dst_v = new uint8_t[v_plane_size];
54
55 int counter = 0; // Counter to form frame names.
56 bool success = false; // Is conversion successful.
57
58 while (true) {
59 std::string file_name = FormFrameName(4, counter);
60 // Get full path file name.
61 std::string input_file_name = FindFullFileName(frames_dir, file_name);
62
63 if (FileExists(input_file_name)) {
64 ++counter; // Update counter for the next round.
65 } else {
66 fprintf(stdout, "Reached end of frames list\n");
67 break;
68 }
69
70 // Read the RGBA frame into rgba_buffer.
71 ReadRGBAFrame(input_file_name.c_str(), input_frame_size, rgba_buffer);
72
73 // Delete the input frame.
74 if (delete_frames) {
75 if (remove(input_file_name.c_str()) != 0) {
76 fprintf(stderr, "Cannot delete file %s\n", input_file_name.c_str());
77 }
78 }
79
80 // Convert to I420 frame.
81 libyuv::ABGRToI420(rgba_buffer, SrcStrideFrame(), dst_y, DstStrideY(),
82 dst_u, DstStrideU(), dst_v, DstStrideV(), width_,
83 height_);
84
85 // Add the I420 frame to the YUV video file.
86 success = AddYUVToFile(dst_y, y_plane_size, dst_u, u_plane_size, dst_v,
87 v_plane_size, output_file);
88
89 if (!success) {
90 fprintf(stderr, "LibYUV error during RGBA to I420 frame conversion\n");
91 break;
92 }
93 }
94
95 delete[] rgba_buffer;
96 delete[] dst_y;
97 delete[] dst_u;
98 delete[] dst_v;
99
100 fclose(output_file);
101
102 return success;
103 }
104
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)105 bool Converter::AddYUVToFile(uint8_t* y_plane,
106 int y_plane_size,
107 uint8_t* u_plane,
108 int u_plane_size,
109 uint8_t* v_plane,
110 int v_plane_size,
111 FILE* output_file) {
112 bool success = AddYUVPlaneToFile(y_plane, y_plane_size, output_file) &&
113 AddYUVPlaneToFile(u_plane, u_plane_size, output_file) &&
114 AddYUVPlaneToFile(v_plane, v_plane_size, output_file);
115 return success;
116 }
117
AddYUVPlaneToFile(uint8_t * yuv_plane,int yuv_plane_size,FILE * file)118 bool Converter::AddYUVPlaneToFile(uint8_t* yuv_plane,
119 int yuv_plane_size,
120 FILE* file) {
121 size_t bytes_written = fwrite(yuv_plane, 1, yuv_plane_size, file);
122
123 if (bytes_written != static_cast<size_t>(yuv_plane_size)) {
124 fprintf(stderr,
125 "Number of bytes written (%d) doesn't match size of y plane"
126 " (%d)\n",
127 static_cast<int>(bytes_written), yuv_plane_size);
128 return false;
129 }
130 return true;
131 }
132
ReadRGBAFrame(const char * input_file_name,int input_frame_size,unsigned char * buffer)133 bool Converter::ReadRGBAFrame(const char* input_file_name,
134 int input_frame_size,
135 unsigned char* buffer) {
136 FILE* input_file = fopen(input_file_name, "rb");
137 if (input_file == NULL) {
138 fprintf(stderr, "Couldn't open input file for reading: %s\n",
139 input_file_name);
140 return false;
141 }
142
143 size_t nbr_read = fread(buffer, 1, input_frame_size, input_file);
144 fclose(input_file);
145
146 if (nbr_read != static_cast<size_t>(input_frame_size)) {
147 fprintf(stderr, "Error reading from input file: %s\n", input_file_name);
148 return false;
149 }
150
151 return true;
152 }
153
FindFullFileName(std::string dir_name,std::string file_name)154 std::string Converter::FindFullFileName(std::string dir_name,
155 std::string file_name) {
156 return dir_name + SEPARATOR + file_name;
157 }
158
FileExists(std::string file_name_to_check)159 bool Converter::FileExists(std::string file_name_to_check) {
160 struct STAT file_info;
161 int result = STAT(file_name_to_check.c_str(), &file_info);
162 return (result == 0);
163 }
164
FormFrameName(int width,int number)165 std::string Converter::FormFrameName(int width, int number) {
166 std::stringstream tmp;
167
168 // Zero-pad number to a string.
169 tmp << std::setfill('0') << std::setw(width) << number;
170
171 return "frame_" + tmp.str();
172 }
173
174 } // namespace test
175 } // namespace webrtc
176