/src/libavif/ext/aom/av1/encoder/lookahead.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2016, 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 | | #include <assert.h> |
12 | | #include <stdlib.h> |
13 | | |
14 | | #include "config/aom_config.h" |
15 | | |
16 | | #include "aom_scale/yv12config.h" |
17 | | #include "av1/common/common.h" |
18 | | #include "av1/encoder/encoder.h" |
19 | | #include "av1/encoder/extend.h" |
20 | | #include "av1/encoder/lookahead.h" |
21 | | |
22 | | /* Return the buffer at the given absolute index and increment the index */ |
23 | 236k | static struct lookahead_entry *pop(struct lookahead_ctx *ctx, int *idx) { |
24 | 236k | int index = *idx; |
25 | 236k | struct lookahead_entry *buf = ctx->buf + index; |
26 | | |
27 | 236k | assert(index < ctx->max_sz); |
28 | 236k | if (++index >= ctx->max_sz) index -= ctx->max_sz; |
29 | 236k | *idx = index; |
30 | 236k | return buf; |
31 | 236k | } |
32 | | |
33 | 66.8k | void av1_lookahead_destroy(struct lookahead_ctx *ctx) { |
34 | 66.8k | if (ctx) { |
35 | 66.8k | if (ctx->buf) { |
36 | 66.8k | int i; |
37 | | |
38 | 391k | for (i = 0; i < ctx->max_sz; i++) aom_free_frame_buffer(&ctx->buf[i].img); |
39 | 66.8k | free(ctx->buf); |
40 | 66.8k | } |
41 | 66.8k | free(ctx); |
42 | 66.8k | } |
43 | 66.8k | } |
44 | | |
45 | | struct lookahead_ctx *av1_lookahead_init( |
46 | | int width, int height, int subsampling_x, int subsampling_y, |
47 | | int use_highbitdepth, int depth, int border_in_pixels, int byte_alignment, |
48 | 66.8k | int num_lap_buffers, bool is_all_intra, bool alloc_pyramid) { |
49 | 66.8k | int lag_in_frames = AOMMAX(1, depth); |
50 | | |
51 | | // For all-intra frame encoding, previous source frames are not required. |
52 | | // Hence max_pre_frames is set to 0 in this case. As previous source frames |
53 | | // are accessed using a negative index to av1_lookahead_peek(), setting |
54 | | // max_pre_frames to 0 will cause av1_lookahead_peek() to return NULL for a |
55 | | // negative index. |
56 | 66.8k | const uint8_t max_pre_frames = is_all_intra ? 0 : MAX_PRE_FRAMES; |
57 | | |
58 | | // Add the lags to depth and clamp |
59 | 66.8k | depth += num_lap_buffers; |
60 | 66.8k | depth = clamp(depth, 1, MAX_TOTAL_BUFFERS); |
61 | | |
62 | | // Allocate memory to keep previous source frames available. |
63 | 66.8k | depth += max_pre_frames; |
64 | | |
65 | | // Allocate the lookahead structures |
66 | 66.8k | struct lookahead_ctx *ctx = calloc(1, sizeof(*ctx)); |
67 | 66.8k | if (ctx) { |
68 | 66.8k | ctx->max_sz = depth; |
69 | 66.8k | ctx->push_frame_count = 0; |
70 | 66.8k | ctx->max_pre_frames = max_pre_frames; |
71 | 66.8k | ctx->read_ctxs[ENCODE_STAGE].pop_sz = ctx->max_sz - ctx->max_pre_frames; |
72 | 66.8k | ctx->read_ctxs[ENCODE_STAGE].valid = 1; |
73 | 66.8k | if (num_lap_buffers) { |
74 | 6.92k | ctx->read_ctxs[LAP_STAGE].pop_sz = lag_in_frames; |
75 | 6.92k | ctx->read_ctxs[LAP_STAGE].valid = 1; |
76 | 6.92k | } |
77 | 66.8k | ctx->buf = calloc(depth, sizeof(*ctx->buf)); |
78 | 66.8k | if (!ctx->buf) goto fail; |
79 | 391k | for (int i = 0; i < depth; i++) { |
80 | 324k | if (aom_realloc_frame_buffer( |
81 | 324k | &ctx->buf[i].img, width, height, subsampling_x, subsampling_y, |
82 | 324k | use_highbitdepth, border_in_pixels, byte_alignment, NULL, NULL, |
83 | 324k | NULL, alloc_pyramid, 0)) { |
84 | 0 | goto fail; |
85 | 0 | } |
86 | 324k | } |
87 | 66.8k | } |
88 | 66.8k | return ctx; |
89 | 0 | fail: |
90 | 0 | av1_lookahead_destroy(ctx); |
91 | 0 | return NULL; |
92 | 66.8k | } |
93 | | |
94 | 0 | int av1_lookahead_full(const struct lookahead_ctx *ctx) { |
95 | | // TODO(angiebird): Test this function. |
96 | 0 | return ctx->read_ctxs[ENCODE_STAGE].sz >= ctx->read_ctxs[ENCODE_STAGE].pop_sz; |
97 | 0 | } |
98 | | |
99 | | int av1_lookahead_push(struct lookahead_ctx *ctx, const YV12_BUFFER_CONFIG *src, |
100 | | int64_t ts_start, int64_t ts_end, int use_highbitdepth, |
101 | 108k | bool alloc_pyramid, aom_enc_frame_flags_t flags) { |
102 | 108k | int width = src->y_crop_width; |
103 | 108k | int height = src->y_crop_height; |
104 | 108k | int uv_width = src->uv_crop_width; |
105 | 108k | int uv_height = src->uv_crop_height; |
106 | 108k | int subsampling_x = src->subsampling_x; |
107 | 108k | int subsampling_y = src->subsampling_y; |
108 | 108k | int larger_dimensions, new_dimensions; |
109 | | |
110 | 108k | assert(ctx->read_ctxs[ENCODE_STAGE].valid == 1); |
111 | 108k | if (ctx->read_ctxs[ENCODE_STAGE].sz + ctx->max_pre_frames > ctx->max_sz) |
112 | 0 | return 1; |
113 | | |
114 | 108k | ctx->read_ctxs[ENCODE_STAGE].sz++; |
115 | 108k | if (ctx->read_ctxs[LAP_STAGE].valid) { |
116 | 18.7k | ctx->read_ctxs[LAP_STAGE].sz++; |
117 | 18.7k | } |
118 | | |
119 | 108k | struct lookahead_entry *buf = pop(ctx, &ctx->write_idx); |
120 | | |
121 | 108k | new_dimensions = width != buf->img.y_crop_width || |
122 | 108k | height != buf->img.y_crop_height || |
123 | 108k | uv_width != buf->img.uv_crop_width || |
124 | 108k | uv_height != buf->img.uv_crop_height; |
125 | 108k | larger_dimensions = |
126 | 108k | width > buf->img.y_crop_width || height > buf->img.y_crop_height || |
127 | 108k | uv_width > buf->img.uv_crop_width || uv_height > buf->img.uv_crop_height; |
128 | 108k | assert(!larger_dimensions || new_dimensions); |
129 | | |
130 | 108k | if (larger_dimensions) { |
131 | 0 | YV12_BUFFER_CONFIG new_img; |
132 | 0 | memset(&new_img, 0, sizeof(new_img)); |
133 | 0 | if (aom_alloc_frame_buffer(&new_img, width, height, subsampling_x, |
134 | 0 | subsampling_y, use_highbitdepth, |
135 | 0 | AOM_BORDER_IN_PIXELS, 0, alloc_pyramid, 0)) |
136 | 0 | return 1; |
137 | 0 | aom_free_frame_buffer(&buf->img); |
138 | 0 | buf->img = new_img; |
139 | 108k | } else if (new_dimensions) { |
140 | 0 | buf->img.y_width = src->y_width; |
141 | 0 | buf->img.y_height = src->y_height; |
142 | 0 | buf->img.uv_width = src->uv_width; |
143 | 0 | buf->img.uv_height = src->uv_height; |
144 | 0 | buf->img.y_crop_width = src->y_crop_width; |
145 | 0 | buf->img.y_crop_height = src->y_crop_height; |
146 | 0 | buf->img.uv_crop_width = src->uv_crop_width; |
147 | 0 | buf->img.uv_crop_height = src->uv_crop_height; |
148 | 0 | buf->img.subsampling_x = src->subsampling_x; |
149 | 0 | buf->img.subsampling_y = src->subsampling_y; |
150 | 0 | } |
151 | 108k | av1_copy_and_extend_frame(src, &buf->img); |
152 | | |
153 | 108k | buf->ts_start = ts_start; |
154 | 108k | buf->ts_end = ts_end; |
155 | 108k | buf->display_idx = ctx->push_frame_count; |
156 | 108k | buf->flags = flags; |
157 | 108k | ++ctx->push_frame_count; |
158 | 108k | aom_remove_metadata_from_frame_buffer(&buf->img); |
159 | 108k | if (src->metadata && |
160 | 0 | aom_copy_metadata_to_frame_buffer(&buf->img, src->metadata)) { |
161 | 0 | return 1; |
162 | 0 | } |
163 | 108k | return 0; |
164 | 108k | } |
165 | | |
166 | | struct lookahead_entry *av1_lookahead_pop(struct lookahead_ctx *ctx, int drain, |
167 | 127k | COMPRESSOR_STAGE stage) { |
168 | 127k | struct lookahead_entry *buf = NULL; |
169 | 127k | if (ctx) { |
170 | 127k | struct read_ctx *read_ctx = &ctx->read_ctxs[stage]; |
171 | 127k | assert(read_ctx->valid == 1); |
172 | 127k | if (read_ctx->sz && (drain || read_ctx->sz == read_ctx->pop_sz)) { |
173 | 127k | buf = pop(ctx, &read_ctx->read_idx); |
174 | 127k | read_ctx->sz--; |
175 | 127k | } |
176 | 127k | } |
177 | 127k | return buf; |
178 | 127k | } |
179 | | |
180 | | struct lookahead_entry *av1_lookahead_peek(struct lookahead_ctx *ctx, int index, |
181 | 828k | COMPRESSOR_STAGE stage) { |
182 | 828k | struct lookahead_entry *buf = NULL; |
183 | 828k | if (ctx == NULL) { |
184 | 0 | return buf; |
185 | 0 | } |
186 | | |
187 | 828k | struct read_ctx *read_ctx = &ctx->read_ctxs[stage]; |
188 | 828k | assert(read_ctx->valid == 1); |
189 | 828k | if (index >= 0) { |
190 | | // Forward peek |
191 | 774k | if (index < read_ctx->sz) { |
192 | 546k | index += read_ctx->read_idx; |
193 | 546k | if (index >= ctx->max_sz) index -= ctx->max_sz; |
194 | 546k | buf = ctx->buf + index; |
195 | 546k | } |
196 | 774k | } else if (index < 0) { |
197 | | // Backward peek |
198 | 53.6k | if (-index <= ctx->max_pre_frames) { |
199 | 53.6k | index += (int)(read_ctx->read_idx); |
200 | 53.6k | if (index < 0) index += (int)(ctx->max_sz); |
201 | 53.6k | buf = ctx->buf + index; |
202 | 53.6k | } |
203 | 53.6k | } |
204 | | |
205 | 828k | return buf; |
206 | 828k | } |
207 | | |
208 | 368k | int av1_lookahead_depth(struct lookahead_ctx *ctx, COMPRESSOR_STAGE stage) { |
209 | 368k | assert(ctx != NULL); |
210 | | |
211 | 368k | struct read_ctx *read_ctx = &ctx->read_ctxs[stage]; |
212 | 368k | assert(read_ctx->valid == 1); |
213 | 368k | return read_ctx->sz; |
214 | 368k | } |
215 | | |
216 | 356k | int av1_lookahead_pop_sz(struct lookahead_ctx *ctx, COMPRESSOR_STAGE stage) { |
217 | 356k | assert(ctx != NULL); |
218 | | |
219 | 356k | struct read_ctx *read_ctx = &ctx->read_ctxs[stage]; |
220 | | assert(read_ctx->valid == 1); |
221 | 356k | return read_ctx->pop_sz; |
222 | 356k | } |