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