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