Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / libvpx / source / libvpx / examples / vp8_multi_resolution_encoder.c
1 /*
2  *  Copyright (c) 2010 The WebM 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
12 // This is an example demonstrating multi-resolution encoding in VP8.
13 // High-resolution input video is down-sampled to lower-resolutions. The
14 // encoder then encodes the video and outputs multiple bitstreams with
15 // different resolutions.
16 //
17 // Configure with --enable-multi-res-encoding flag to enable this example.
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include "third_party/libyuv/include/libyuv/basic_types.h"
24 #include "third_party/libyuv/include/libyuv/scale.h"
25 #include "third_party/libyuv/include/libyuv/cpu_id.h"
26
27 #include "vpx/vpx_encoder.h"
28 #include "vpx/vp8cx.h"
29
30 #include "./tools_common.h"
31 #include "./video_writer.h"
32
33 // The input video frame is downsampled several times to generate a
34 // multi-level  hierarchical structure. kNumEncoders is defined as the number
35 // of encoding  levels required. For example, if the size of input video is
36 // 1280x720, kNumEncoders is 3, and down-sampling factor is 2, the encoder
37 // outputs 3 bitstreams with resolution of 1280x720(level 0),
38 // 640x360(level 1), and 320x180(level 2) respectively.
39 #define kNumEncoders 3
40
41 static const char *exec_name;
42
43 void usage_exit() {
44   fprintf(stderr,
45           "Usage: %s <width> <height> <infile> <outfile(s)> <output psnr?>\n",
46           exec_name);
47   exit(EXIT_FAILURE);
48 }
49
50 int main(int argc, char *argv[]) {
51   int frame_cnt = 0;
52   FILE *infile = NULL;
53   VpxVideoWriter *writers[kNumEncoders];
54   vpx_codec_ctx_t codec[kNumEncoders];
55   vpx_codec_enc_cfg_t cfg[kNumEncoders];
56   vpx_image_t raw[kNumEncoders];
57   const VpxInterface *const encoder = get_vpx_encoder_by_name("vp8");
58   // Currently, only realtime mode is supported in multi-resolution encoding.
59   const int arg_deadline = VPX_DL_REALTIME;
60   int i;
61   int width = 0;
62   int height = 0;
63   int frame_avail = 0;
64   int got_data = 0;
65
66   // Set show_psnr to 1/0 to show/not show PSNR. Choose show_psnr=0 if you
67   // don't need to know PSNR, which will skip PSNR calculation and save
68   // encoding time.
69   int show_psnr = 0;
70   uint64_t psnr_sse_total[kNumEncoders] = {0};
71   uint64_t psnr_samples_total[kNumEncoders] = {0};
72   double psnr_totals[kNumEncoders][4] = {{0, 0}};
73   int psnr_count[kNumEncoders] = {0};
74
75   // Set the required target bitrates for each resolution level.
76   // If target bitrate for highest-resolution level is set to 0,
77   // (i.e. target_bitrate[0]=0), we skip encoding at that level.
78   unsigned int target_bitrate[kNumEncoders] = {1000, 500, 100};
79
80   // Enter the frame rate of the input video.
81   const int framerate = 30;
82   // Set down-sampling factor for each resolution level.
83   //   dsf[0] controls down sampling from level 0 to level 1;
84   //   dsf[1] controls down sampling from level 1 to level 2;
85   //   dsf[2] is not used.
86   vpx_rational_t dsf[kNumEncoders] = {{2, 1}, {2, 1}, {1, 1}};
87
88   exec_name = argv[0];
89
90   if (!encoder)
91     die("Unsupported codec.");
92
93   // exe_name, input width, input height, input file,
94   // output file 1, output file 2, output file 3, psnr on/off
95   if (argc != (5 + kNumEncoders))
96     die("Invalid number of input options.");
97
98   printf("Using %s\n", vpx_codec_iface_name(encoder->codec_interface()));
99
100   width = strtol(argv[1], NULL, 0);
101   height = strtol(argv[2], NULL, 0);
102
103   if (width < 16 || width % 2 || height < 16 || height % 2)
104     die("Invalid resolution: %ldx%ld", width, height);
105
106   // Open input video file for encoding
107   if (!(infile = fopen(argv[3], "rb")))
108     die("Failed to open %s for reading", argv[3]);
109
110   show_psnr = strtol(argv[kNumEncoders + 4], NULL, 0);
111
112   // Populate default encoder configuration
113   for (i = 0; i < kNumEncoders; ++i) {
114     vpx_codec_err_t res =
115         vpx_codec_enc_config_default(encoder->codec_interface(), &cfg[i], 0);
116     if (res != VPX_CODEC_OK) {
117       printf("Failed to get config: %s\n", vpx_codec_err_to_string(res));
118       return EXIT_FAILURE;
119     }
120   }
121
122   // Update the default configuration according to needs of the application.
123   // Highest-resolution encoder settings
124   cfg[0].g_w = width;
125   cfg[0].g_h = height;
126   cfg[0].g_threads = 1;
127   cfg[0].rc_dropframe_thresh = 30;
128   cfg[0].rc_end_usage = VPX_CBR;
129   cfg[0].rc_resize_allowed = 0;
130   cfg[0].rc_min_quantizer = 4;
131   cfg[0].rc_max_quantizer = 56;
132   cfg[0].rc_undershoot_pct = 98;
133   cfg[0].rc_overshoot_pct = 100;
134   cfg[0].rc_buf_initial_sz = 500;
135   cfg[0].rc_buf_optimal_sz = 600;
136   cfg[0].rc_buf_sz = 1000;
137   cfg[0].g_error_resilient = 1;
138   cfg[0].g_lag_in_frames = 0;
139   cfg[0].kf_mode = VPX_KF_AUTO;  // VPX_KF_DISABLED
140   cfg[0].kf_min_dist = 3000;
141   cfg[0].kf_max_dist = 3000;
142   cfg[0].rc_target_bitrate = target_bitrate[0];
143   cfg[0].g_timebase.num = 1;
144   cfg[0].g_timebase.den = framerate;
145
146   // Other-resolution encoder settings
147   for (i = 1; i < kNumEncoders; ++i) {
148     cfg[i] = cfg[0];
149     cfg[i].g_threads = 1;
150     cfg[i].rc_target_bitrate = target_bitrate[i];
151
152     // Note: Width & height of other-resolution encoders are calculated
153     // from the highest-resolution encoder's size and the corresponding
154     // down_sampling_factor.
155     {
156       unsigned int iw = cfg[i - 1].g_w * dsf[i - 1].den + dsf[i - 1].num - 1;
157       unsigned int ih = cfg[i - 1].g_h * dsf[i - 1].den + dsf[i - 1].num - 1;
158       cfg[i].g_w = iw / dsf[i - 1].num;
159       cfg[i].g_h = ih / dsf[i - 1].num;
160     }
161
162     // Make width & height to be multiplier of 2.
163     if ((cfg[i].g_w) % 2)
164       cfg[i].g_w++;
165
166     if ((cfg[i].g_h) % 2)
167       cfg[i].g_h++;
168   }
169
170   // Open output file for each encoder to output bitstreams
171   for (i = 0; i < kNumEncoders; ++i) {
172     VpxVideoInfo info = {
173       encoder->fourcc,
174       cfg[i].g_w,
175       cfg[i].g_h,
176       {cfg[i].g_timebase.num, cfg[i].g_timebase.den}
177     };
178
179     if (!(writers[i] = vpx_video_writer_open(argv[i+4], kContainerIVF, &info)))
180       die("Failed to open %s for writing", argv[i+4]);
181   }
182
183   // Allocate image for each encoder
184   for (i = 0; i < kNumEncoders; ++i)
185     if (!vpx_img_alloc(&raw[i], VPX_IMG_FMT_I420, cfg[i].g_w, cfg[i].g_h, 32))
186       die("Failed to allocate image", cfg[i].g_w, cfg[i].g_h);
187
188   // Initialize multi-encoder
189   if (vpx_codec_enc_init_multi(&codec[0], encoder->codec_interface(), &cfg[0],
190                                kNumEncoders,
191                                show_psnr ? VPX_CODEC_USE_PSNR : 0, &dsf[0]))
192     die_codec(&codec[0], "Failed to initialize encoder");
193
194   // The extra encoding configuration parameters can be set as follows.
195   for (i = 0; i < kNumEncoders; i++) {
196     // Set encoding speed
197     if (vpx_codec_control(&codec[i], VP8E_SET_CPUUSED, -6))
198       die_codec(&codec[i], "Failed to set cpu_used");
199
200     // Set static threshold.
201     if (vpx_codec_control(&codec[i], VP8E_SET_STATIC_THRESHOLD, 1))
202       die_codec(&codec[i], "Failed to set static threshold");
203
204     // Set NOISE_SENSITIVITY to do TEMPORAL_DENOISING
205     // Enable denoising for the highest-resolution encoder.
206     if (vpx_codec_control(&codec[0], VP8E_SET_NOISE_SENSITIVITY, i == 0))
207       die_codec(&codec[0], "Failed to set noise_sensitivity");
208   }
209
210   frame_avail = 1;
211   got_data = 0;
212
213   while (frame_avail || got_data) {
214     vpx_codec_iter_t iter[kNumEncoders] = {NULL};
215     const vpx_codec_cx_pkt_t *pkt[kNumEncoders];
216
217     frame_avail = vpx_img_read(&raw[0], infile);
218
219     if (frame_avail) {
220       for (i = 1; i < kNumEncoders; ++i) {
221         vpx_image_t *const prev = &raw[i - 1];
222
223         // Scale the image down a number of times by downsampling factor
224         // FilterMode 1 or 2 give better psnr than FilterMode 0.
225         I420Scale(prev->planes[VPX_PLANE_Y], prev->stride[VPX_PLANE_Y],
226                   prev->planes[VPX_PLANE_U], prev->stride[VPX_PLANE_U],
227                   prev->planes[VPX_PLANE_V], prev->stride[VPX_PLANE_V],
228                   prev->d_w, prev->d_h,
229                   raw[i].planes[VPX_PLANE_Y], raw[i].stride[VPX_PLANE_Y],
230                   raw[i].planes[VPX_PLANE_U], raw[i].stride[VPX_PLANE_U],
231                   raw[i].planes[VPX_PLANE_V], raw[i].stride[VPX_PLANE_V],
232                   raw[i].d_w, raw[i].d_h, 1);
233       }
234     }
235
236     // Encode frame.
237     if (vpx_codec_encode(&codec[0], frame_avail? &raw[0] : NULL,
238                          frame_cnt, 1, 0, arg_deadline)) {
239       die_codec(&codec[0], "Failed to encode frame");
240     }
241
242     for (i = kNumEncoders - 1; i >= 0; i--) {
243       got_data = 0;
244
245       while ((pkt[i] = vpx_codec_get_cx_data(&codec[i], &iter[i]))) {
246         got_data = 1;
247         switch (pkt[i]->kind) {
248           case VPX_CODEC_CX_FRAME_PKT:
249             vpx_video_writer_write_frame(writers[i], pkt[i]->data.frame.buf,
250                                          pkt[i]->data.frame.sz, frame_cnt - 1);
251           break;
252           case VPX_CODEC_PSNR_PKT:
253             if (show_psnr) {
254               int j;
255               psnr_sse_total[i] += pkt[i]->data.psnr.sse[0];
256               psnr_samples_total[i] += pkt[i]->data.psnr.samples[0];
257               for (j = 0; j < 4; j++)
258                 psnr_totals[i][j] += pkt[i]->data.psnr.psnr[j];
259               psnr_count[i]++;
260             }
261             break;
262           default:
263             break;
264         }
265         printf(pkt[i]->kind == VPX_CODEC_CX_FRAME_PKT &&
266                (pkt[i]->data.frame.flags & VPX_FRAME_IS_KEY)? "K":".");
267         fflush(stdout);
268       }
269     }
270     frame_cnt++;
271   }
272   printf("\n");
273
274   fclose(infile);
275
276   printf("Processed %d frames.\n", frame_cnt - 1);
277   for (i = 0; i < kNumEncoders; ++i) {
278     // Calculate PSNR and print it out
279     if (show_psnr && psnr_count[i] > 0) {
280       int j;
281       double ovpsnr = sse_to_psnr(psnr_samples_total[i], 255.0,
282                                   psnr_sse_total[i]);
283
284       fprintf(stderr, "\n ENC%d PSNR (Overall/Avg/Y/U/V)", i);
285       fprintf(stderr, " %.3lf", ovpsnr);
286       for (j = 0; j < 4; j++)
287         fprintf(stderr, " %.3lf", psnr_totals[i][j]/psnr_count[i]);
288     }
289
290     if (vpx_codec_destroy(&codec[i]))
291       die_codec(&codec[i], "Failed to destroy codec");
292
293     vpx_img_free(&raw[i]);
294     vpx_video_writer_close(writers[i]);
295   }
296   printf("\n");
297
298   return EXIT_SUCCESS;
299 }