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