• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <math.h>
12 #include <stdarg.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 
17 #include "./tools_common.h"
18 
19 #if CONFIG_VP8_ENCODER || CONFIG_VP9_ENCODER
20 #include "vpx/vp8cx.h"
21 #endif
22 
23 #if CONFIG_VP8_DECODER || CONFIG_VP9_DECODER
24 #include "vpx/vp8dx.h"
25 #endif
26 
27 #if defined(_WIN32) || defined(__OS2__)
28 #include <io.h>
29 #include <fcntl.h>
30 
31 #ifdef __OS2__
32 #define _setmode setmode
33 #define _fileno fileno
34 #define _O_BINARY O_BINARY
35 #endif
36 #endif
37 
38 #define LOG_ERROR(label)               \
39   do {                                 \
40     const char *l = label;             \
41     va_list ap;                        \
42     va_start(ap, fmt);                 \
43     if (l) fprintf(stderr, "%s: ", l); \
44     vfprintf(stderr, fmt, ap);         \
45     fprintf(stderr, "\n");             \
46     va_end(ap);                        \
47   } while (0)
48 
set_binary_mode(FILE * stream)49 FILE *set_binary_mode(FILE *stream) {
50   (void)stream;
51 #if defined(_WIN32) || defined(__OS2__)
52   _setmode(_fileno(stream), _O_BINARY);
53 #endif
54   return stream;
55 }
56 
die(const char * fmt,...)57 void die(const char *fmt, ...) {
58   LOG_ERROR(NULL);
59   usage_exit();
60 }
61 
fatal(const char * fmt,...)62 void fatal(const char *fmt, ...) {
63   LOG_ERROR("Fatal");
64   exit(EXIT_FAILURE);
65 }
66 
warn(const char * fmt,...)67 void warn(const char *fmt, ...) { LOG_ERROR("Warning"); }
68 
die_codec(vpx_codec_ctx_t * ctx,const char * s)69 void die_codec(vpx_codec_ctx_t *ctx, const char *s) {
70   const char *detail = vpx_codec_error_detail(ctx);
71 
72   printf("%s: %s\n", s, vpx_codec_error(ctx));
73   if (detail) printf("    %s\n", detail);
74   exit(EXIT_FAILURE);
75 }
76 
read_yuv_frame(struct VpxInputContext * input_ctx,vpx_image_t * yuv_frame)77 int read_yuv_frame(struct VpxInputContext *input_ctx, vpx_image_t *yuv_frame) {
78   FILE *f = input_ctx->file;
79   struct FileTypeDetectionBuffer *detect = &input_ctx->detect;
80   int plane = 0;
81   int shortread = 0;
82   const int bytespp = (yuv_frame->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1;
83 
84   for (plane = 0; plane < 3; ++plane) {
85     uint8_t *ptr;
86     const int w = vpx_img_plane_width(yuv_frame, plane);
87     const int h = vpx_img_plane_height(yuv_frame, plane);
88     int r;
89 
90     /* Determine the correct plane based on the image format. The for-loop
91      * always counts in Y,U,V order, but this may not match the order of
92      * the data on disk.
93      */
94     switch (plane) {
95       case 1:
96         ptr =
97             yuv_frame->planes[yuv_frame->fmt == VPX_IMG_FMT_YV12 ? VPX_PLANE_V
98                                                                  : VPX_PLANE_U];
99         break;
100       case 2:
101         ptr =
102             yuv_frame->planes[yuv_frame->fmt == VPX_IMG_FMT_YV12 ? VPX_PLANE_U
103                                                                  : VPX_PLANE_V];
104         break;
105       default: ptr = yuv_frame->planes[plane];
106     }
107 
108     for (r = 0; r < h; ++r) {
109       size_t needed = w * bytespp;
110       size_t buf_position = 0;
111       const size_t left = detect->buf_read - detect->position;
112       if (left > 0) {
113         const size_t more = (left < needed) ? left : needed;
114         memcpy(ptr, detect->buf + detect->position, more);
115         buf_position = more;
116         needed -= more;
117         detect->position += more;
118       }
119       if (needed > 0) {
120         shortread |= (fread(ptr + buf_position, 1, needed, f) < needed);
121       }
122 
123       ptr += yuv_frame->stride[plane];
124     }
125   }
126 
127   return shortread;
128 }
129 
130 #if CONFIG_ENCODERS
131 
132 static const VpxInterface vpx_encoders[] = {
133 #if CONFIG_VP8_ENCODER
134   { "vp8", VP8_FOURCC, &vpx_codec_vp8_cx },
135 #endif
136 
137 #if CONFIG_VP9_ENCODER
138   { "vp9", VP9_FOURCC, &vpx_codec_vp9_cx },
139 #endif
140 };
141 
get_vpx_encoder_count(void)142 int get_vpx_encoder_count(void) {
143   return sizeof(vpx_encoders) / sizeof(vpx_encoders[0]);
144 }
145 
get_vpx_encoder_by_index(int i)146 const VpxInterface *get_vpx_encoder_by_index(int i) { return &vpx_encoders[i]; }
147 
get_vpx_encoder_by_name(const char * name)148 const VpxInterface *get_vpx_encoder_by_name(const char *name) {
149   int i;
150 
151   for (i = 0; i < get_vpx_encoder_count(); ++i) {
152     const VpxInterface *encoder = get_vpx_encoder_by_index(i);
153     if (strcmp(encoder->name, name) == 0) return encoder;
154   }
155 
156   return NULL;
157 }
158 
159 #endif  // CONFIG_ENCODERS
160 
161 #if CONFIG_DECODERS
162 
163 static const VpxInterface vpx_decoders[] = {
164 #if CONFIG_VP8_DECODER
165   { "vp8", VP8_FOURCC, &vpx_codec_vp8_dx },
166 #endif
167 
168 #if CONFIG_VP9_DECODER
169   { "vp9", VP9_FOURCC, &vpx_codec_vp9_dx },
170 #endif
171 };
172 
get_vpx_decoder_count(void)173 int get_vpx_decoder_count(void) {
174   return sizeof(vpx_decoders) / sizeof(vpx_decoders[0]);
175 }
176 
get_vpx_decoder_by_index(int i)177 const VpxInterface *get_vpx_decoder_by_index(int i) { return &vpx_decoders[i]; }
178 
get_vpx_decoder_by_name(const char * name)179 const VpxInterface *get_vpx_decoder_by_name(const char *name) {
180   int i;
181 
182   for (i = 0; i < get_vpx_decoder_count(); ++i) {
183     const VpxInterface *const decoder = get_vpx_decoder_by_index(i);
184     if (strcmp(decoder->name, name) == 0) return decoder;
185   }
186 
187   return NULL;
188 }
189 
get_vpx_decoder_by_fourcc(uint32_t fourcc)190 const VpxInterface *get_vpx_decoder_by_fourcc(uint32_t fourcc) {
191   int i;
192 
193   for (i = 0; i < get_vpx_decoder_count(); ++i) {
194     const VpxInterface *const decoder = get_vpx_decoder_by_index(i);
195     if (decoder->fourcc == fourcc) return decoder;
196   }
197 
198   return NULL;
199 }
200 
201 #endif  // CONFIG_DECODERS
202 
203 // TODO(dkovalev): move this function to vpx_image.{c, h}, so it will be part
204 // of vpx_image_t support
vpx_img_plane_width(const vpx_image_t * img,int plane)205 int vpx_img_plane_width(const vpx_image_t *img, int plane) {
206   if (plane > 0 && img->x_chroma_shift > 0)
207     return (img->d_w + 1) >> img->x_chroma_shift;
208   else
209     return img->d_w;
210 }
211 
vpx_img_plane_height(const vpx_image_t * img,int plane)212 int vpx_img_plane_height(const vpx_image_t *img, int plane) {
213   if (plane > 0 && img->y_chroma_shift > 0)
214     return (img->d_h + 1) >> img->y_chroma_shift;
215   else
216     return img->d_h;
217 }
218 
vpx_img_write(const vpx_image_t * img,FILE * file)219 void vpx_img_write(const vpx_image_t *img, FILE *file) {
220   int plane;
221 
222   for (plane = 0; plane < 3; ++plane) {
223     const unsigned char *buf = img->planes[plane];
224     const int stride = img->stride[plane];
225     const int w = vpx_img_plane_width(img, plane) *
226                   ((img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1);
227     const int h = vpx_img_plane_height(img, plane);
228     int y;
229 
230     for (y = 0; y < h; ++y) {
231       fwrite(buf, 1, w, file);
232       buf += stride;
233     }
234   }
235 }
236 
vpx_img_read(vpx_image_t * img,FILE * file)237 int vpx_img_read(vpx_image_t *img, FILE *file) {
238   int plane;
239 
240   for (plane = 0; plane < 3; ++plane) {
241     unsigned char *buf = img->planes[plane];
242     const int stride = img->stride[plane];
243     const int w = vpx_img_plane_width(img, plane) *
244                   ((img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1);
245     const int h = vpx_img_plane_height(img, plane);
246     int y;
247 
248     for (y = 0; y < h; ++y) {
249       if (fread(buf, 1, w, file) != (size_t)w) return 0;
250       buf += stride;
251     }
252   }
253 
254   return 1;
255 }
256 
257 // TODO(dkovalev) change sse_to_psnr signature: double -> int64_t
sse_to_psnr(double samples,double peak,double sse)258 double sse_to_psnr(double samples, double peak, double sse) {
259   static const double kMaxPSNR = 100.0;
260 
261   if (sse > 0.0) {
262     const double psnr = 10.0 * log10(samples * peak * peak / sse);
263     return psnr > kMaxPSNR ? kMaxPSNR : psnr;
264   } else {
265     return kMaxPSNR;
266   }
267 }
268 
269 // TODO(debargha): Consolidate the functions below into a separate file.
270 #if CONFIG_VP9_HIGHBITDEPTH
highbd_img_upshift(vpx_image_t * dst,vpx_image_t * src,int input_shift)271 static void highbd_img_upshift(vpx_image_t *dst, vpx_image_t *src,
272                                int input_shift) {
273   // Note the offset is 1 less than half.
274   const int offset = input_shift > 0 ? (1 << (input_shift - 1)) - 1 : 0;
275   int plane;
276   if (dst->d_w != src->d_w || dst->d_h != src->d_h ||
277       dst->x_chroma_shift != src->x_chroma_shift ||
278       dst->y_chroma_shift != src->y_chroma_shift || dst->fmt != src->fmt ||
279       input_shift < 0) {
280     fatal("Unsupported image conversion");
281   }
282   switch (src->fmt) {
283     case VPX_IMG_FMT_I42016:
284     case VPX_IMG_FMT_I42216:
285     case VPX_IMG_FMT_I44416:
286     case VPX_IMG_FMT_I44016: break;
287     default: fatal("Unsupported image conversion"); break;
288   }
289   for (plane = 0; plane < 3; plane++) {
290     int w = src->d_w;
291     int h = src->d_h;
292     int x, y;
293     if (plane) {
294       w = (w + src->x_chroma_shift) >> src->x_chroma_shift;
295       h = (h + src->y_chroma_shift) >> src->y_chroma_shift;
296     }
297     for (y = 0; y < h; y++) {
298       uint16_t *p_src =
299           (uint16_t *)(src->planes[plane] + y * src->stride[plane]);
300       uint16_t *p_dst =
301           (uint16_t *)(dst->planes[plane] + y * dst->stride[plane]);
302       for (x = 0; x < w; x++) *p_dst++ = (*p_src++ << input_shift) + offset;
303     }
304   }
305 }
306 
lowbd_img_upshift(vpx_image_t * dst,vpx_image_t * src,int input_shift)307 static void lowbd_img_upshift(vpx_image_t *dst, vpx_image_t *src,
308                               int input_shift) {
309   // Note the offset is 1 less than half.
310   const int offset = input_shift > 0 ? (1 << (input_shift - 1)) - 1 : 0;
311   int plane;
312   if (dst->d_w != src->d_w || dst->d_h != src->d_h ||
313       dst->x_chroma_shift != src->x_chroma_shift ||
314       dst->y_chroma_shift != src->y_chroma_shift ||
315       dst->fmt != src->fmt + VPX_IMG_FMT_HIGHBITDEPTH || input_shift < 0) {
316     fatal("Unsupported image conversion");
317   }
318   switch (src->fmt) {
319     case VPX_IMG_FMT_I420:
320     case VPX_IMG_FMT_I422:
321     case VPX_IMG_FMT_I444:
322     case VPX_IMG_FMT_I440: break;
323     default: fatal("Unsupported image conversion"); break;
324   }
325   for (plane = 0; plane < 3; plane++) {
326     int w = src->d_w;
327     int h = src->d_h;
328     int x, y;
329     if (plane) {
330       w = (w + src->x_chroma_shift) >> src->x_chroma_shift;
331       h = (h + src->y_chroma_shift) >> src->y_chroma_shift;
332     }
333     for (y = 0; y < h; y++) {
334       uint8_t *p_src = src->planes[plane] + y * src->stride[plane];
335       uint16_t *p_dst =
336           (uint16_t *)(dst->planes[plane] + y * dst->stride[plane]);
337       for (x = 0; x < w; x++) {
338         *p_dst++ = (*p_src++ << input_shift) + offset;
339       }
340     }
341   }
342 }
343 
vpx_img_upshift(vpx_image_t * dst,vpx_image_t * src,int input_shift)344 void vpx_img_upshift(vpx_image_t *dst, vpx_image_t *src, int input_shift) {
345   if (src->fmt & VPX_IMG_FMT_HIGHBITDEPTH) {
346     highbd_img_upshift(dst, src, input_shift);
347   } else {
348     lowbd_img_upshift(dst, src, input_shift);
349   }
350 }
351 
vpx_img_truncate_16_to_8(vpx_image_t * dst,vpx_image_t * src)352 void vpx_img_truncate_16_to_8(vpx_image_t *dst, vpx_image_t *src) {
353   int plane;
354   if (dst->fmt + VPX_IMG_FMT_HIGHBITDEPTH != src->fmt || dst->d_w != src->d_w ||
355       dst->d_h != src->d_h || dst->x_chroma_shift != src->x_chroma_shift ||
356       dst->y_chroma_shift != src->y_chroma_shift) {
357     fatal("Unsupported image conversion");
358   }
359   switch (dst->fmt) {
360     case VPX_IMG_FMT_I420:
361     case VPX_IMG_FMT_I422:
362     case VPX_IMG_FMT_I444:
363     case VPX_IMG_FMT_I440: break;
364     default: fatal("Unsupported image conversion"); break;
365   }
366   for (plane = 0; plane < 3; plane++) {
367     int w = src->d_w;
368     int h = src->d_h;
369     int x, y;
370     if (plane) {
371       w = (w + src->x_chroma_shift) >> src->x_chroma_shift;
372       h = (h + src->y_chroma_shift) >> src->y_chroma_shift;
373     }
374     for (y = 0; y < h; y++) {
375       uint16_t *p_src =
376           (uint16_t *)(src->planes[plane] + y * src->stride[plane]);
377       uint8_t *p_dst = dst->planes[plane] + y * dst->stride[plane];
378       for (x = 0; x < w; x++) {
379         *p_dst++ = (uint8_t)(*p_src++);
380       }
381     }
382   }
383 }
384 
highbd_img_downshift(vpx_image_t * dst,vpx_image_t * src,int down_shift)385 static void highbd_img_downshift(vpx_image_t *dst, vpx_image_t *src,
386                                  int down_shift) {
387   int plane;
388   if (dst->d_w != src->d_w || dst->d_h != src->d_h ||
389       dst->x_chroma_shift != src->x_chroma_shift ||
390       dst->y_chroma_shift != src->y_chroma_shift || dst->fmt != src->fmt ||
391       down_shift < 0) {
392     fatal("Unsupported image conversion");
393   }
394   switch (src->fmt) {
395     case VPX_IMG_FMT_I42016:
396     case VPX_IMG_FMT_I42216:
397     case VPX_IMG_FMT_I44416:
398     case VPX_IMG_FMT_I44016: break;
399     default: fatal("Unsupported image conversion"); break;
400   }
401   for (plane = 0; plane < 3; plane++) {
402     int w = src->d_w;
403     int h = src->d_h;
404     int x, y;
405     if (plane) {
406       w = (w + src->x_chroma_shift) >> src->x_chroma_shift;
407       h = (h + src->y_chroma_shift) >> src->y_chroma_shift;
408     }
409     for (y = 0; y < h; y++) {
410       uint16_t *p_src =
411           (uint16_t *)(src->planes[plane] + y * src->stride[plane]);
412       uint16_t *p_dst =
413           (uint16_t *)(dst->planes[plane] + y * dst->stride[plane]);
414       for (x = 0; x < w; x++) *p_dst++ = *p_src++ >> down_shift;
415     }
416   }
417 }
418 
lowbd_img_downshift(vpx_image_t * dst,vpx_image_t * src,int down_shift)419 static void lowbd_img_downshift(vpx_image_t *dst, vpx_image_t *src,
420                                 int down_shift) {
421   int plane;
422   if (dst->d_w != src->d_w || dst->d_h != src->d_h ||
423       dst->x_chroma_shift != src->x_chroma_shift ||
424       dst->y_chroma_shift != src->y_chroma_shift ||
425       src->fmt != dst->fmt + VPX_IMG_FMT_HIGHBITDEPTH || down_shift < 0) {
426     fatal("Unsupported image conversion");
427   }
428   switch (dst->fmt) {
429     case VPX_IMG_FMT_I420:
430     case VPX_IMG_FMT_I422:
431     case VPX_IMG_FMT_I444:
432     case VPX_IMG_FMT_I440: break;
433     default: fatal("Unsupported image conversion"); break;
434   }
435   for (plane = 0; plane < 3; plane++) {
436     int w = src->d_w;
437     int h = src->d_h;
438     int x, y;
439     if (plane) {
440       w = (w + src->x_chroma_shift) >> src->x_chroma_shift;
441       h = (h + src->y_chroma_shift) >> src->y_chroma_shift;
442     }
443     for (y = 0; y < h; y++) {
444       uint16_t *p_src =
445           (uint16_t *)(src->planes[plane] + y * src->stride[plane]);
446       uint8_t *p_dst = dst->planes[plane] + y * dst->stride[plane];
447       for (x = 0; x < w; x++) {
448         *p_dst++ = *p_src++ >> down_shift;
449       }
450     }
451   }
452 }
453 
vpx_img_downshift(vpx_image_t * dst,vpx_image_t * src,int down_shift)454 void vpx_img_downshift(vpx_image_t *dst, vpx_image_t *src, int down_shift) {
455   if (dst->fmt & VPX_IMG_FMT_HIGHBITDEPTH) {
456     highbd_img_downshift(dst, src, down_shift);
457   } else {
458     lowbd_img_downshift(dst, src, down_shift);
459   }
460 }
461 #endif  // CONFIG_VP9_HIGHBITDEPTH
462