xref: /aosp_15_r20/external/libaom/examples/scalable_decoder.c (revision 77c1e3ccc04c968bd2bc212e87364f250e820521)
1*77c1e3ccSAndroid Build Coastguard Worker /*
2*77c1e3ccSAndroid Build Coastguard Worker  * Copyright (c) 2018, Alliance for Open Media. All rights reserved.
3*77c1e3ccSAndroid Build Coastguard Worker  *
4*77c1e3ccSAndroid Build Coastguard Worker  * This source code is subject to the terms of the BSD 2 Clause License and
5*77c1e3ccSAndroid Build Coastguard Worker  * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6*77c1e3ccSAndroid Build Coastguard Worker  * was not distributed with this source code in the LICENSE file, you can
7*77c1e3ccSAndroid Build Coastguard Worker  * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8*77c1e3ccSAndroid Build Coastguard Worker  * Media Patent License 1.0 was not distributed with this source code in the
9*77c1e3ccSAndroid Build Coastguard Worker  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10*77c1e3ccSAndroid Build Coastguard Worker  */
11*77c1e3ccSAndroid Build Coastguard Worker 
12*77c1e3ccSAndroid Build Coastguard Worker // Scalable Decoder
13*77c1e3ccSAndroid Build Coastguard Worker // ==============
14*77c1e3ccSAndroid Build Coastguard Worker //
15*77c1e3ccSAndroid Build Coastguard Worker // This is an example of a scalable decoder loop. It takes a 2-spatial-layer
16*77c1e3ccSAndroid Build Coastguard Worker // input file
17*77c1e3ccSAndroid Build Coastguard Worker // containing the compressed data (in OBU format), passes it through the
18*77c1e3ccSAndroid Build Coastguard Worker // decoder, and writes the decompressed frames to disk. The base layer and
19*77c1e3ccSAndroid Build Coastguard Worker // enhancement layers are stored as separate files, out_lyr0.yuv and
20*77c1e3ccSAndroid Build Coastguard Worker // out_lyr1.yuv, respectively.
21*77c1e3ccSAndroid Build Coastguard Worker //
22*77c1e3ccSAndroid Build Coastguard Worker // Standard Includes
23*77c1e3ccSAndroid Build Coastguard Worker // -----------------
24*77c1e3ccSAndroid Build Coastguard Worker // For decoders, you only have to include `aom_decoder.h` and then any
25*77c1e3ccSAndroid Build Coastguard Worker // header files for the specific codecs you use. In this case, we're using
26*77c1e3ccSAndroid Build Coastguard Worker // av1.
27*77c1e3ccSAndroid Build Coastguard Worker //
28*77c1e3ccSAndroid Build Coastguard Worker // Initializing The Codec
29*77c1e3ccSAndroid Build Coastguard Worker // ----------------------
30*77c1e3ccSAndroid Build Coastguard Worker // The libaom decoder is initialized by the call to aom_codec_dec_init().
31*77c1e3ccSAndroid Build Coastguard Worker // Determining the codec interface to use is handled by AvxVideoReader and the
32*77c1e3ccSAndroid Build Coastguard Worker // functions prefixed with aom_video_reader_. Discussion of those functions is
33*77c1e3ccSAndroid Build Coastguard Worker // beyond the scope of this example, but the main gist is to open the input file
34*77c1e3ccSAndroid Build Coastguard Worker // and parse just enough of it to determine if it's a AVx file and which AVx
35*77c1e3ccSAndroid Build Coastguard Worker // codec is contained within the file.
36*77c1e3ccSAndroid Build Coastguard Worker // Note the NULL pointer passed to aom_codec_dec_init(). We do that in this
37*77c1e3ccSAndroid Build Coastguard Worker // example because we want the algorithm to determine the stream configuration
38*77c1e3ccSAndroid Build Coastguard Worker // (width/height) and allocate memory automatically.
39*77c1e3ccSAndroid Build Coastguard Worker //
40*77c1e3ccSAndroid Build Coastguard Worker // Decoding A Frame
41*77c1e3ccSAndroid Build Coastguard Worker // ----------------
42*77c1e3ccSAndroid Build Coastguard Worker // Once the frame has been read into memory, it is decoded using the
43*77c1e3ccSAndroid Build Coastguard Worker // `aom_codec_decode` function. The call takes a pointer to the data
44*77c1e3ccSAndroid Build Coastguard Worker // (`frame`) and the length of the data (`frame_size`). No application data
45*77c1e3ccSAndroid Build Coastguard Worker // is associated with the frame in this example, so the `user_priv`
46*77c1e3ccSAndroid Build Coastguard Worker // parameter is NULL. The `deadline` parameter is left at zero for this
47*77c1e3ccSAndroid Build Coastguard Worker // example. This parameter is generally only used when doing adaptive post
48*77c1e3ccSAndroid Build Coastguard Worker // processing.
49*77c1e3ccSAndroid Build Coastguard Worker //
50*77c1e3ccSAndroid Build Coastguard Worker // Codecs may produce a variable number of output frames for every call to
51*77c1e3ccSAndroid Build Coastguard Worker // `aom_codec_decode`. These frames are retrieved by the
52*77c1e3ccSAndroid Build Coastguard Worker // `aom_codec_get_frame` iterator function. The iterator variable `iter` is
53*77c1e3ccSAndroid Build Coastguard Worker // initialized to NULL each time `aom_codec_decode` is called.
54*77c1e3ccSAndroid Build Coastguard Worker // `aom_codec_get_frame` is called in a loop, returning a pointer to a
55*77c1e3ccSAndroid Build Coastguard Worker // decoded image or NULL to indicate the end of list.
56*77c1e3ccSAndroid Build Coastguard Worker //
57*77c1e3ccSAndroid Build Coastguard Worker // Processing The Decoded Data
58*77c1e3ccSAndroid Build Coastguard Worker // ---------------------------
59*77c1e3ccSAndroid Build Coastguard Worker // In this example, we simply write the encoded data to disk. It is
60*77c1e3ccSAndroid Build Coastguard Worker // important to honor the image's `stride` values.
61*77c1e3ccSAndroid Build Coastguard Worker //
62*77c1e3ccSAndroid Build Coastguard Worker // Cleanup
63*77c1e3ccSAndroid Build Coastguard Worker // -------
64*77c1e3ccSAndroid Build Coastguard Worker // The `aom_codec_destroy` call frees any memory allocated by the codec.
65*77c1e3ccSAndroid Build Coastguard Worker //
66*77c1e3ccSAndroid Build Coastguard Worker // Error Handling
67*77c1e3ccSAndroid Build Coastguard Worker // --------------
68*77c1e3ccSAndroid Build Coastguard Worker // This example does not special case any error return codes. If there was
69*77c1e3ccSAndroid Build Coastguard Worker // an error, a descriptive message is printed and the program exits. With
70*77c1e3ccSAndroid Build Coastguard Worker // few exceptions, aom_codec functions return an enumerated error status,
71*77c1e3ccSAndroid Build Coastguard Worker // with the value `0` indicating success.
72*77c1e3ccSAndroid Build Coastguard Worker 
73*77c1e3ccSAndroid Build Coastguard Worker #include <stdio.h>
74*77c1e3ccSAndroid Build Coastguard Worker #include <stdlib.h>
75*77c1e3ccSAndroid Build Coastguard Worker #include <string.h>
76*77c1e3ccSAndroid Build Coastguard Worker 
77*77c1e3ccSAndroid Build Coastguard Worker #include "aom/aom_decoder.h"
78*77c1e3ccSAndroid Build Coastguard Worker #include "aom/aomdx.h"
79*77c1e3ccSAndroid Build Coastguard Worker #include "common/obudec.h"
80*77c1e3ccSAndroid Build Coastguard Worker #include "common/tools_common.h"
81*77c1e3ccSAndroid Build Coastguard Worker #include "common/video_reader.h"
82*77c1e3ccSAndroid Build Coastguard Worker 
83*77c1e3ccSAndroid Build Coastguard Worker static const char *exec_name;
84*77c1e3ccSAndroid Build Coastguard Worker 
85*77c1e3ccSAndroid Build Coastguard Worker #define MAX_LAYERS 5
86*77c1e3ccSAndroid Build Coastguard Worker 
usage_exit(void)87*77c1e3ccSAndroid Build Coastguard Worker void usage_exit(void) {
88*77c1e3ccSAndroid Build Coastguard Worker   fprintf(stderr, "Usage: %s <infile>\n", exec_name);
89*77c1e3ccSAndroid Build Coastguard Worker   exit(EXIT_FAILURE);
90*77c1e3ccSAndroid Build Coastguard Worker }
91*77c1e3ccSAndroid Build Coastguard Worker 
main(int argc,char ** argv)92*77c1e3ccSAndroid Build Coastguard Worker int main(int argc, char **argv) {
93*77c1e3ccSAndroid Build Coastguard Worker   int frame_cnt = 0;
94*77c1e3ccSAndroid Build Coastguard Worker   FILE *outfile[MAX_LAYERS];
95*77c1e3ccSAndroid Build Coastguard Worker   char filename[80];
96*77c1e3ccSAndroid Build Coastguard Worker   FILE *inputfile = NULL;
97*77c1e3ccSAndroid Build Coastguard Worker   uint8_t *buf = NULL;
98*77c1e3ccSAndroid Build Coastguard Worker   size_t bytes_in_buffer = 0;
99*77c1e3ccSAndroid Build Coastguard Worker   size_t buffer_size = 0;
100*77c1e3ccSAndroid Build Coastguard Worker   struct AvxInputContext aom_input_ctx;
101*77c1e3ccSAndroid Build Coastguard Worker   struct ObuDecInputContext obu_ctx = { &aom_input_ctx, NULL, 0, 0, 0 };
102*77c1e3ccSAndroid Build Coastguard Worker   aom_codec_stream_info_t si;
103*77c1e3ccSAndroid Build Coastguard Worker   uint8_t tmpbuf[32];
104*77c1e3ccSAndroid Build Coastguard Worker   unsigned int i;
105*77c1e3ccSAndroid Build Coastguard Worker 
106*77c1e3ccSAndroid Build Coastguard Worker   exec_name = argv[0];
107*77c1e3ccSAndroid Build Coastguard Worker 
108*77c1e3ccSAndroid Build Coastguard Worker   if (argc != 2) die("Invalid number of arguments.");
109*77c1e3ccSAndroid Build Coastguard Worker 
110*77c1e3ccSAndroid Build Coastguard Worker   if (!(inputfile = fopen(argv[1], "rb")))
111*77c1e3ccSAndroid Build Coastguard Worker     die("Failed to open %s for read.", argv[1]);
112*77c1e3ccSAndroid Build Coastguard Worker   obu_ctx.avx_ctx->file = inputfile;
113*77c1e3ccSAndroid Build Coastguard Worker   obu_ctx.avx_ctx->filename = argv[1];
114*77c1e3ccSAndroid Build Coastguard Worker 
115*77c1e3ccSAndroid Build Coastguard Worker   aom_codec_iface_t *decoder = get_aom_decoder_by_index(0);
116*77c1e3ccSAndroid Build Coastguard Worker   printf("Using %s\n", aom_codec_iface_name(decoder));
117*77c1e3ccSAndroid Build Coastguard Worker 
118*77c1e3ccSAndroid Build Coastguard Worker   aom_codec_ctx_t codec;
119*77c1e3ccSAndroid Build Coastguard Worker   if (aom_codec_dec_init(&codec, decoder, NULL, 0))
120*77c1e3ccSAndroid Build Coastguard Worker     die("Failed to initialize decoder.");
121*77c1e3ccSAndroid Build Coastguard Worker 
122*77c1e3ccSAndroid Build Coastguard Worker   if (aom_codec_control(&codec, AV1D_SET_OUTPUT_ALL_LAYERS, 1)) {
123*77c1e3ccSAndroid Build Coastguard Worker     die_codec(&codec, "Failed to set output_all_layers control.");
124*77c1e3ccSAndroid Build Coastguard Worker   }
125*77c1e3ccSAndroid Build Coastguard Worker 
126*77c1e3ccSAndroid Build Coastguard Worker   // peak sequence header OBU to get number of spatial layers
127*77c1e3ccSAndroid Build Coastguard Worker   const size_t ret = fread(tmpbuf, 1, 32, inputfile);
128*77c1e3ccSAndroid Build Coastguard Worker   if (ret != 32) die_codec(&codec, "Input is not a valid obu file");
129*77c1e3ccSAndroid Build Coastguard Worker   si.is_annexb = 0;
130*77c1e3ccSAndroid Build Coastguard Worker   if (aom_codec_peek_stream_info(decoder, tmpbuf, 32, &si)) {
131*77c1e3ccSAndroid Build Coastguard Worker     die_codec(&codec, "Input is not a valid obu file");
132*77c1e3ccSAndroid Build Coastguard Worker   }
133*77c1e3ccSAndroid Build Coastguard Worker   fseek(inputfile, -32, SEEK_CUR);
134*77c1e3ccSAndroid Build Coastguard Worker 
135*77c1e3ccSAndroid Build Coastguard Worker   if (!file_is_obu(&obu_ctx))
136*77c1e3ccSAndroid Build Coastguard Worker     die_codec(&codec, "Input is not a valid obu file");
137*77c1e3ccSAndroid Build Coastguard Worker 
138*77c1e3ccSAndroid Build Coastguard Worker   // open base layer output yuv file
139*77c1e3ccSAndroid Build Coastguard Worker   snprintf(filename, sizeof(filename), "out_lyr%d.yuv", 0);
140*77c1e3ccSAndroid Build Coastguard Worker   if (!(outfile[0] = fopen(filename, "wb")))
141*77c1e3ccSAndroid Build Coastguard Worker     die("Failed top open output for writing.");
142*77c1e3ccSAndroid Build Coastguard Worker 
143*77c1e3ccSAndroid Build Coastguard Worker   // open any enhancement layer output yuv files
144*77c1e3ccSAndroid Build Coastguard Worker   for (i = 1; i < si.number_spatial_layers; i++) {
145*77c1e3ccSAndroid Build Coastguard Worker     snprintf(filename, sizeof(filename), "out_lyr%u.yuv", i);
146*77c1e3ccSAndroid Build Coastguard Worker     if (!(outfile[i] = fopen(filename, "wb")))
147*77c1e3ccSAndroid Build Coastguard Worker       die("Failed to open output for writing.");
148*77c1e3ccSAndroid Build Coastguard Worker   }
149*77c1e3ccSAndroid Build Coastguard Worker 
150*77c1e3ccSAndroid Build Coastguard Worker   while (!obudec_read_temporal_unit(&obu_ctx, &buf, &bytes_in_buffer,
151*77c1e3ccSAndroid Build Coastguard Worker                                     &buffer_size)) {
152*77c1e3ccSAndroid Build Coastguard Worker     aom_codec_iter_t iter = NULL;
153*77c1e3ccSAndroid Build Coastguard Worker     aom_image_t *img = NULL;
154*77c1e3ccSAndroid Build Coastguard Worker     if (aom_codec_decode(&codec, buf, bytes_in_buffer, NULL))
155*77c1e3ccSAndroid Build Coastguard Worker       die_codec(&codec, "Failed to decode frame.");
156*77c1e3ccSAndroid Build Coastguard Worker 
157*77c1e3ccSAndroid Build Coastguard Worker     while ((img = aom_codec_get_frame(&codec, &iter)) != NULL) {
158*77c1e3ccSAndroid Build Coastguard Worker       aom_image_t *img_shifted =
159*77c1e3ccSAndroid Build Coastguard Worker           aom_img_alloc(NULL, AOM_IMG_FMT_I420, img->d_w, img->d_h, 16);
160*77c1e3ccSAndroid Build Coastguard Worker       img_shifted->bit_depth = 8;
161*77c1e3ccSAndroid Build Coastguard Worker       aom_img_downshift(img_shifted, img,
162*77c1e3ccSAndroid Build Coastguard Worker                         img->bit_depth - img_shifted->bit_depth);
163*77c1e3ccSAndroid Build Coastguard Worker       if (img->spatial_id == 0) {
164*77c1e3ccSAndroid Build Coastguard Worker         printf("Writing        base layer 0 %d\n", frame_cnt);
165*77c1e3ccSAndroid Build Coastguard Worker         aom_img_write(img_shifted, outfile[0]);
166*77c1e3ccSAndroid Build Coastguard Worker       } else if (img->spatial_id <= (int)(si.number_spatial_layers - 1)) {
167*77c1e3ccSAndroid Build Coastguard Worker         printf("Writing enhancement layer %d %d\n", img->spatial_id, frame_cnt);
168*77c1e3ccSAndroid Build Coastguard Worker         aom_img_write(img_shifted, outfile[img->spatial_id]);
169*77c1e3ccSAndroid Build Coastguard Worker       } else {
170*77c1e3ccSAndroid Build Coastguard Worker         die_codec(&codec, "Invalid bitstream. Layer id exceeds layer count");
171*77c1e3ccSAndroid Build Coastguard Worker       }
172*77c1e3ccSAndroid Build Coastguard Worker       if (img->spatial_id == (int)(si.number_spatial_layers - 1)) ++frame_cnt;
173*77c1e3ccSAndroid Build Coastguard Worker     }
174*77c1e3ccSAndroid Build Coastguard Worker   }
175*77c1e3ccSAndroid Build Coastguard Worker 
176*77c1e3ccSAndroid Build Coastguard Worker   printf("Processed %d frames.\n", frame_cnt);
177*77c1e3ccSAndroid Build Coastguard Worker   if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec");
178*77c1e3ccSAndroid Build Coastguard Worker 
179*77c1e3ccSAndroid Build Coastguard Worker   for (i = 0; i < si.number_spatial_layers; i++) fclose(outfile[i]);
180*77c1e3ccSAndroid Build Coastguard Worker 
181*77c1e3ccSAndroid Build Coastguard Worker   fclose(inputfile);
182*77c1e3ccSAndroid Build Coastguard Worker 
183*77c1e3ccSAndroid Build Coastguard Worker   return EXIT_SUCCESS;
184*77c1e3ccSAndroid Build Coastguard Worker }
185