Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / webrtc / modules / video_coding / codecs / vp8 / vp8_sequence_coder.cc
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
11 #include "testing/gtest/include/gtest/gtest.h"
12 #include "webrtc/common_video/interface/i420_video_frame.h"
13 #include "webrtc/common_video/interface/video_image.h"
14 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
15 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h"
16 #include "webrtc/system_wrappers/interface/scoped_ptr.h"
17 #include "webrtc/system_wrappers/interface/tick_util.h"
18 #include "webrtc/test/testsupport/fileutils.h"
19 #include "webrtc/test/testsupport/metrics/video_metrics.h"
20 #include "webrtc/tools/simple_command_line_parser.h"
21
22 class Vp8SequenceCoderEncodeCallback : public webrtc::EncodedImageCallback {
23  public:
24   explicit Vp8SequenceCoderEncodeCallback(FILE* encoded_file)
25       : encoded_file_(encoded_file),
26         encoded_bytes_(0) {}
27   ~Vp8SequenceCoderEncodeCallback();
28   int Encoded(webrtc::EncodedImage& encoded_image,
29               const webrtc::CodecSpecificInfo* codecSpecificInfo,
30               const webrtc::RTPFragmentationHeader*);
31   // Returns the encoded image.
32   webrtc::EncodedImage encoded_image() { return encoded_image_; }
33   int encoded_bytes() { return encoded_bytes_; }
34  private:
35   webrtc::EncodedImage encoded_image_;
36   FILE* encoded_file_;
37   int encoded_bytes_;
38 };
39
40 Vp8SequenceCoderEncodeCallback::~Vp8SequenceCoderEncodeCallback() {
41   delete [] encoded_image_._buffer;
42   encoded_image_._buffer = NULL;
43 }
44 int Vp8SequenceCoderEncodeCallback::Encoded(
45     webrtc::EncodedImage& encoded_image,
46     const webrtc::CodecSpecificInfo* codecSpecificInfo,
47     const webrtc::RTPFragmentationHeader* fragmentation) {
48   if (encoded_image_._size < encoded_image._size) {
49     delete [] encoded_image_._buffer;
50     encoded_image_._buffer = NULL;
51     encoded_image_._buffer = new uint8_t[encoded_image._size];
52     encoded_image_._size = encoded_image._size;
53   }
54   memcpy(encoded_image_._buffer, encoded_image._buffer, encoded_image._size);
55   encoded_image_._length = encoded_image._length;
56   if (encoded_file_ != NULL) {
57     if (fwrite(encoded_image._buffer, 1, encoded_image._length,
58                encoded_file_) != encoded_image._length) {
59       return -1;
60     }
61   }
62   encoded_bytes_ += encoded_image_._length;
63   return 0;
64 }
65
66 // TODO(mikhal): Add support for varying the frame size.
67 class Vp8SequenceCoderDecodeCallback : public webrtc::DecodedImageCallback {
68  public:
69   explicit Vp8SequenceCoderDecodeCallback(FILE* decoded_file)
70       : decoded_file_(decoded_file) {}
71   int Decoded(webrtc::I420VideoFrame& frame);
72   bool DecodeComplete();
73
74  private:
75   FILE* decoded_file_;
76 };
77
78 int Vp8SequenceCoderDecodeCallback::Decoded(webrtc::I420VideoFrame& image) {
79   EXPECT_EQ(0, webrtc::PrintI420VideoFrame(image, decoded_file_));
80   return 0;
81 }
82
83 int SequenceCoder(webrtc::test::CommandLineParser& parser) {
84   int width = strtol((parser.GetFlag("w")).c_str(), NULL, 10);
85   int height = strtol((parser.GetFlag("h")).c_str(), NULL, 10);
86   int framerate = strtol((parser.GetFlag("f")).c_str(), NULL, 10);
87
88   if (width <= 0 || height <= 0 || framerate <= 0) {
89     fprintf(stderr, "Error: Resolution cannot be <= 0!\n");
90     return -1;
91   }
92   int target_bitrate = strtol((parser.GetFlag("b")).c_str(), NULL, 10);
93   if (target_bitrate <= 0) {
94     fprintf(stderr, "Error: Bit-rate cannot be <= 0!\n");
95     return -1;
96   }
97
98   // SetUp
99   // Open input file.
100   std::string encoded_file_name = parser.GetFlag("encoded_file");
101   FILE* encoded_file = fopen(encoded_file_name.c_str(), "wb");
102   if (encoded_file == NULL) {
103     fprintf(stderr, "Error: Cannot open encoded file\n");
104     return -1;
105   }
106   std::string input_file_name = parser.GetFlag("input_file");
107   FILE* input_file = fopen(input_file_name.c_str(), "rb");
108   if (input_file == NULL) {
109     fprintf(stderr, "Error: Cannot open input file\n");
110     return -1;
111   }
112   // Open output file.
113   std::string output_file_name = parser.GetFlag("output_file");
114   FILE* output_file = fopen(output_file_name.c_str(), "wb");
115   if (output_file == NULL) {
116     fprintf(stderr, "Error: Cannot open output file\n");
117     return -1;
118   }
119
120   // Get range of frames: will encode num_frames following start_frame).
121   int start_frame = strtol((parser.GetFlag("start_frame")).c_str(), NULL, 10);
122   int num_frames = strtol((parser.GetFlag("num_frames")).c_str(), NULL, 10);
123
124   // Codec SetUp.
125   webrtc::VideoCodec inst;
126   memset(&inst, 0, sizeof(inst));
127   webrtc::VP8Encoder* encoder = webrtc::VP8Encoder::Create();
128   webrtc::VP8Decoder* decoder = webrtc::VP8Decoder::Create();
129   inst.codecType = webrtc::kVideoCodecVP8;
130   inst.codecSpecific.VP8.feedbackModeOn = false;
131   inst.codecSpecific.VP8.denoisingOn = true;
132   inst.maxFramerate = framerate;
133   inst.startBitrate = target_bitrate;
134   inst.maxBitrate = 8000;
135   inst.width = width;
136   inst.height = height;
137
138   if (encoder->InitEncode(&inst, 1, 1440) < 0) {
139     fprintf(stderr, "Error: Cannot initialize vp8 encoder\n");
140     return -1;
141   }
142   EXPECT_EQ(0, decoder->InitDecode(&inst, 1));
143   webrtc::I420VideoFrame input_frame;
144   unsigned int length = webrtc::CalcBufferSize(webrtc::kI420, width, height);
145   webrtc::scoped_ptr<uint8_t[]> frame_buffer(new uint8_t[length]);
146
147   int half_width = (width + 1) / 2;
148   // Set and register callbacks.
149   Vp8SequenceCoderEncodeCallback encoder_callback(encoded_file);
150   encoder->RegisterEncodeCompleteCallback(&encoder_callback);
151   Vp8SequenceCoderDecodeCallback decoder_callback(output_file);
152   decoder->RegisterDecodeCompleteCallback(&decoder_callback);
153   // Read->Encode->Decode sequence.
154   // num_frames = -1 implies unlimited encoding (entire sequence).
155   int64_t starttime = webrtc::TickTime::MillisecondTimestamp();
156   int frame_cnt = 1;
157   int frames_processed = 0;
158   input_frame.CreateEmptyFrame(width, height, width, half_width, half_width);
159   while (!feof(input_file) &&
160       (num_frames == -1 || frames_processed < num_frames)) {
161      if (fread(frame_buffer.get(), 1, length, input_file) != length)
162       continue;
163     if (frame_cnt >= start_frame) {
164       webrtc::ConvertToI420(webrtc::kI420, frame_buffer.get(), 0, 0,
165                             width, height, 0, webrtc::kRotateNone,
166                             &input_frame);
167       encoder->Encode(input_frame, NULL, NULL);
168       decoder->Decode(encoder_callback.encoded_image(), false, NULL);
169       ++frames_processed;
170     }
171     ++frame_cnt;
172   }
173   printf("\nProcessed %d frames\n", frames_processed);
174   int64_t endtime = webrtc::TickTime::MillisecondTimestamp();
175   int64_t totalExecutionTime = endtime - starttime;
176   printf("Total execution time: %.2lf ms\n",
177          static_cast<double>(totalExecutionTime));
178   int sum_enc_bytes = encoder_callback.encoded_bytes();
179   double actual_bit_rate =  8.0 * sum_enc_bytes /
180       (frame_cnt / inst.maxFramerate);
181   printf("Actual bitrate: %f kbps\n", actual_bit_rate / 1000);
182   webrtc::test::QualityMetricsResult psnr_result, ssim_result;
183   EXPECT_EQ(0, webrtc::test::I420MetricsFromFiles(
184       input_file_name.c_str(), output_file_name.c_str(),
185       inst.width, inst.height,
186       &psnr_result, &ssim_result));
187   printf("PSNR avg: %f[dB], min: %f[dB]\nSSIM avg: %f, min: %f\n",
188           psnr_result.average, psnr_result.min,
189           ssim_result.average, ssim_result.min);
190   return frame_cnt;
191 }
192
193 int main(int argc, char** argv) {
194   std::string program_name = argv[0];
195   std::string usage = "Encode and decodes a video sequence, and writes"
196   "results to a file.\n"
197   "Example usage:\n" + program_name + " functionality"
198   " --w=352 --h=288 --input_file=input.yuv --output_file=output.yuv "
199   " Command line flags:\n"
200   "  - width(int): The width of the input file. Default: 352\n"
201   "  - height(int): The height of the input file. Default: 288\n"
202   "  - input_file(string): The YUV file to encode."
203   "      Default: foreman.yuv\n"
204   "  - encoded_file(string): The vp8 encoded file (encoder output)."
205   "      Default: vp8_encoded.vp8\n"
206   "  - output_file(string): The yuv decoded file (decoder output)."
207   "      Default: vp8_decoded.yuv\n."
208   "  - start_frame - frame number in which encoding will begin. Default: 0"
209   "  - num_frames - Number of frames to be processed. "
210   "      Default: -1 (entire sequence).";
211
212   webrtc::test::CommandLineParser parser;
213
214   // Init the parser and set the usage message.
215   parser.Init(argc, argv);
216
217   // Reset flags.
218   parser.SetFlag("w", "352");
219   parser.SetFlag("h", "288");
220   parser.SetFlag("f", "30");
221   parser.SetFlag("b", "500");
222   parser.SetFlag("start_frame", "0");
223   parser.SetFlag("num_frames", "-1");
224   parser.SetFlag("output_file", webrtc::test::OutputPath() + "vp8_decoded.yuv");
225   parser.SetFlag("encoded_file",
226                  webrtc::test::OutputPath() + "vp8_encoded.vp8");
227   parser.SetFlag("input_file", webrtc::test::ResourcePath("foreman_cif",
228                                                           "yuv"));
229
230   parser.ProcessFlags();
231   if (parser.GetFlag("help") == "true") {
232     parser.PrintUsageMessage();
233   }
234   parser.PrintEnteredFlags();
235
236   return SequenceCoder(parser);
237 }