1 /*
2  * Copyright (c) 2017, Alliance for Open Media. All rights reserved
3  *
4  * This source code is subject to the terms of the BSD 2 Clause License and
5  * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6  * was not distributed with this source code in the LICENSE file, you can
7  * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8  * Media Patent License 1.0 was not distributed with this source code in the
9  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10  */
11 
12 // Lightfield Decoder
13 // ==================
14 //
15 // This is an example of a simple lightfield decoder. It builds upon the
16 // simple_decoder.c example.  It takes an input file containing the compressed
17 // data (in webm format), treating it as a lightfield instead of a video and
18 // will decode a single lightfield tile. The lf_width and lf_height arguments
19 // are the number of lightfield images in each dimension. The tile to decode
20 // is specified by the tile_u, tile_v, tile_s, tile_t arguments. The tile_u,
21 // tile_v specify the image and tile_s, tile_t specify the tile in the image.
22 // After running the lightfield encoder, run lightfield decoder to decode a
23 // single tile:
24 // examples/lightfield_decoder vase10x10.webm vase_tile.yuv 10 10 3 4 5 10 5
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include "aom/aom_decoder.h"
31 #include "aom/aomdx.h"
32 
33 #include "../tools_common.h"
34 #include "../video_reader.h"
35 #include "./aom_config.h"
36 
37 static const char *exec_name;
38 
usage_exit(void)39 void usage_exit(void) {
40   fprintf(stderr,
41           "Usage: %s <infile> <outfile> <lf_width> <lf_height> <tlie_u>"
42           " <tile_v> <tile_s> <tile_t> <lf_blocksize>\n",
43           exec_name);
44   exit(EXIT_FAILURE);
45 }
46 
aom_img_copy(aom_image_t * src,aom_image_t * dst)47 aom_image_t *aom_img_copy(aom_image_t *src, aom_image_t *dst) {
48   dst = aom_img_alloc(dst, src->fmt, src->d_w, src->d_h, 16);
49 
50   int plane;
51 
52   for (plane = 0; plane < 3; ++plane) {
53     uint8_t *src_buf = src->planes[plane];
54     const int src_stride = src->stride[plane];
55     const int src_w = plane == 0 ? src->d_w : src->d_w >> 1;
56     const int src_h = plane == 0 ? src->d_h : src->d_h >> 1;
57 
58     uint8_t *dst_buf = dst->planes[plane];
59     const int dst_stride = dst->stride[plane];
60     int y;
61 
62     for (y = 0; y < src_h; ++y) {
63       memcpy(dst_buf, src_buf, src_w);
64       src_buf += src_stride;
65       dst_buf += dst_stride;
66     }
67   }
68   return dst;
69 }
70 
main(int argc,char ** argv)71 int main(int argc, char **argv) {
72   int frame_cnt = 0;
73   FILE *outfile = NULL;
74   aom_codec_ctx_t codec;
75   AvxVideoReader *reader = NULL;
76   const AvxInterface *decoder = NULL;
77   const AvxVideoInfo *info = NULL;
78   const char *lf_width_arg;
79   const char *lf_height_arg;
80   const char *tile_u_arg;
81   const char *tile_v_arg;
82   const char *tile_s_arg;
83   const char *tile_t_arg;
84   const char *lf_blocksize_arg;
85   int lf_width, lf_height;
86   int tile_u, tile_v, tile_s, tile_t;
87   int lf_blocksize;
88   int u_blocks;
89   int v_blocks;
90 
91   exec_name = argv[0];
92 
93   if (argc != 10) die("Invalid number of arguments.");
94 
95   reader = aom_video_reader_open(argv[1]);
96   if (!reader) die("Failed to open %s for reading.", argv[1]);
97 
98   if (!(outfile = fopen(argv[2], "wb")))
99     die("Failed to open %s for writing.", argv[2]);
100 
101   lf_width_arg = argv[3];
102   lf_height_arg = argv[4];
103   tile_u_arg = argv[5];
104   tile_v_arg = argv[6];
105   tile_s_arg = argv[7];
106   tile_t_arg = argv[8];
107   lf_blocksize_arg = argv[9];
108   lf_width = (int)strtol(lf_width_arg, NULL, 0);
109   lf_height = (int)strtol(lf_height_arg, NULL, 0);
110   tile_u = (int)strtol(tile_u_arg, NULL, 0);
111   tile_v = (int)strtol(tile_v_arg, NULL, 0);
112   tile_s = (int)strtol(tile_s_arg, NULL, 0);
113   tile_t = (int)strtol(tile_t_arg, NULL, 0);
114   lf_blocksize = (int)strtol(lf_blocksize_arg, NULL, 0);
115 
116   info = aom_video_reader_get_info(reader);
117 
118   decoder = get_aom_decoder_by_fourcc(info->codec_fourcc);
119   if (!decoder) die("Unknown input codec.");
120 
121   printf("Using %s\n", aom_codec_iface_name(decoder->codec_interface()));
122 
123   if (aom_codec_dec_init(&codec, decoder->codec_interface(), NULL, 0))
124     die_codec(&codec, "Failed to initialize decoder.");
125 
126   // How many reference images we need to encode.
127   u_blocks = (lf_width + lf_blocksize - 1) / lf_blocksize;
128   v_blocks = (lf_height + lf_blocksize - 1) / lf_blocksize;
129   aom_image_t *reference_images =
130       (aom_image_t *)malloc(u_blocks * v_blocks * sizeof(aom_image_t));
131   for (int bv = 0; bv < v_blocks; ++bv) {
132     for (int bu = 0; bu < u_blocks; ++bu) {
133       aom_video_reader_read_frame(reader);
134       aom_codec_iter_t iter = NULL;
135       aom_image_t *img = NULL;
136       size_t frame_size = 0;
137       const unsigned char *frame =
138           aom_video_reader_get_frame(reader, &frame_size);
139       if (aom_codec_decode(&codec, frame, (unsigned int)frame_size, NULL, 0))
140         die_codec(&codec, "Failed to decode frame.");
141 
142       while ((img = aom_codec_get_frame(&codec, &iter)) != NULL) {
143         aom_img_copy(img, &reference_images[bu + bv * u_blocks]);
144         char name[1024];
145         snprintf(name, sizeof(name), "ref_%d_%d.yuv", bu, bv);
146         printf("writing ref image to %s, %d, %d\n", name, img->d_w, img->d_h);
147         FILE *ref_file = fopen(name, "wb");
148         aom_img_write(img, ref_file);
149         fclose(ref_file);
150         ++frame_cnt;
151       }
152     }
153   }
154 
155   int decode_frame_index = tile_v * lf_width + tile_u;
156   do {
157     aom_video_reader_read_frame(reader);
158   } while (frame_cnt++ != decode_frame_index);
159   size_t frame_size = 0;
160   const unsigned char *frame = aom_video_reader_get_frame(reader, &frame_size);
161 
162   int ref_bu = tile_u / lf_blocksize;
163   int ref_bv = tile_v / lf_blocksize;
164   int ref_bi = ref_bu + ref_bv * u_blocks;
165   av1_ref_frame_t ref;
166   ref.idx = 0;
167   ref.img = reference_images[ref_bi];
168   // This is too slow for real lightfield rendering.  This copies the
169   // reference image bytes.  We need a way to just set a pointer
170   // in order to make this fast enough.
171   if (aom_codec_control(&codec, AV1_SET_REFERENCE, &ref)) {
172     die_codec(&codec, "Failed to set reference image.");
173   }
174   aom_codec_control_(&codec, AV1_SET_DECODE_TILE_ROW, tile_t);
175   aom_codec_control_(&codec, AV1_SET_DECODE_TILE_COL, tile_s);
176   aom_codec_err_t aom_status =
177       aom_codec_decode(&codec, frame, frame_size, NULL, 0);
178   if (aom_status) die_codec(&codec, "Failed to decode tile.");
179   aom_codec_iter_t iter = NULL;
180   aom_image_t *img = aom_codec_get_frame(&codec, &iter);
181   aom_img_write(img, outfile);
182 
183   if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec");
184   aom_video_reader_close(reader);
185   fclose(outfile);
186 
187   return EXIT_SUCCESS;
188 }
189