/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 | 2.52k | static struct lookahead_entry *pop(struct lookahead_ctx *ctx, int *idx) { |
24 | 2.52k | int index = *idx; |
25 | 2.52k | struct lookahead_entry *buf = ctx->buf + index; |
26 | | |
27 | 2.52k | assert(index < ctx->max_sz); |
28 | 2.52k | if (++index >= ctx->max_sz) index -= ctx->max_sz; |
29 | 2.52k | *idx = index; |
30 | 2.52k | return buf; |
31 | 2.52k | } |
32 | | |
33 | 1.26k | void av1_lookahead_destroy(struct lookahead_ctx *ctx) { |
34 | 1.26k | if (ctx) { |
35 | 1.26k | if (ctx->buf) { |
36 | 1.26k | int i; |
37 | | |
38 | 2.52k | for (i = 0; i < ctx->max_sz; i++) aom_free_frame_buffer(&ctx->buf[i].img); |
39 | 1.26k | free(ctx->buf); |
40 | 1.26k | } |
41 | 1.26k | free(ctx); |
42 | 1.26k | } |
43 | 1.26k | } |
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 | 1.26k | bool is_all_intra, int enable_global_motion) { |
50 | 1.26k | 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 | 1.26k | const uint8_t max_pre_frames = is_all_intra ? 0 : MAX_PRE_FRAMES; |
58 | | |
59 | | // Add the lags to depth and clamp |
60 | 1.26k | depth += num_lap_buffers; |
61 | 1.26k | depth = clamp(depth, 1, MAX_TOTAL_BUFFERS); |
62 | | |
63 | | // Allocate memory to keep previous source frames available. |
64 | 1.26k | depth += max_pre_frames; |
65 | | |
66 | | // Allocate the lookahead structures |
67 | 1.26k | struct lookahead_ctx *ctx = calloc(1, sizeof(*ctx)); |
68 | 1.26k | if (ctx) { |
69 | 1.26k | unsigned int i; |
70 | 1.26k | ctx->max_sz = depth; |
71 | 1.26k | ctx->push_frame_count = 0; |
72 | 1.26k | ctx->max_pre_frames = max_pre_frames; |
73 | 1.26k | ctx->read_ctxs[ENCODE_STAGE].pop_sz = ctx->max_sz - ctx->max_pre_frames; |
74 | 1.26k | ctx->read_ctxs[ENCODE_STAGE].valid = 1; |
75 | 1.26k | 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 | 1.26k | ctx->buf = calloc(depth, sizeof(*ctx->buf)); |
80 | 1.26k | if (!ctx->buf) goto fail; |
81 | 2.52k | for (i = 0; i < depth; i++) { |
82 | 1.26k | if (aom_realloc_frame_buffer( |
83 | 1.26k | &ctx->buf[i].img, width, height, subsampling_x, subsampling_y, |
84 | 1.26k | use_highbitdepth, border_in_pixels, byte_alignment, NULL, NULL, |
85 | 1.26k | NULL, enable_global_motion)) |
86 | 0 | goto fail; |
87 | 1.26k | } |
88 | 1.26k | } |
89 | 1.26k | return ctx; |
90 | 0 | fail: |
91 | 0 | av1_lookahead_destroy(ctx); |
92 | 0 | return NULL; |
93 | 1.26k | } |
94 | | |
95 | | int av1_lookahead_push(struct lookahead_ctx *ctx, const YV12_BUFFER_CONFIG *src, |
96 | | int64_t ts_start, int64_t ts_end, int use_highbitdepth, |
97 | 1.26k | aom_enc_frame_flags_t flags) { |
98 | 1.26k | int width = src->y_crop_width; |
99 | 1.26k | int height = src->y_crop_height; |
100 | 1.26k | int uv_width = src->uv_crop_width; |
101 | 1.26k | int uv_height = src->uv_crop_height; |
102 | 1.26k | int subsampling_x = src->subsampling_x; |
103 | 1.26k | int subsampling_y = src->subsampling_y; |
104 | 1.26k | int larger_dimensions, new_dimensions; |
105 | | |
106 | 1.26k | assert(ctx->read_ctxs[ENCODE_STAGE].valid == 1); |
107 | 1.26k | if (ctx->read_ctxs[ENCODE_STAGE].sz + 1 + ctx->max_pre_frames > ctx->max_sz) |
108 | 0 | return 1; |
109 | 1.26k | ctx->read_ctxs[ENCODE_STAGE].sz++; |
110 | 1.26k | if (ctx->read_ctxs[LAP_STAGE].valid) { |
111 | 0 | ctx->read_ctxs[LAP_STAGE].sz++; |
112 | 0 | } |
113 | 1.26k | struct lookahead_entry *buf = pop(ctx, &ctx->write_idx); |
114 | | |
115 | 1.26k | new_dimensions = width != buf->img.y_crop_width || |
116 | 1.26k | height != buf->img.y_crop_height || |
117 | 1.26k | uv_width != buf->img.uv_crop_width || |
118 | 1.26k | uv_height != buf->img.uv_crop_height; |
119 | 1.26k | larger_dimensions = width > buf->img.y_width || height > buf->img.y_height || |
120 | 1.26k | uv_width > buf->img.uv_width || |
121 | 1.26k | uv_height > buf->img.uv_height; |
122 | 1.26k | assert(!larger_dimensions || new_dimensions); |
123 | | |
124 | 1.26k | if (larger_dimensions) { |
125 | 0 | YV12_BUFFER_CONFIG new_img; |
126 | 0 | memset(&new_img, 0, sizeof(new_img)); |
127 | 0 | if (aom_alloc_frame_buffer(&new_img, width, height, subsampling_x, |
128 | 0 | subsampling_y, use_highbitdepth, |
129 | 0 | AOM_BORDER_IN_PIXELS, 0)) |
130 | 0 | return 1; |
131 | 0 | aom_free_frame_buffer(&buf->img); |
132 | 0 | buf->img = new_img; |
133 | 1.26k | } else if (new_dimensions) { |
134 | 0 | buf->img.y_crop_width = src->y_crop_width; |
135 | 0 | buf->img.y_crop_height = src->y_crop_height; |
136 | 0 | buf->img.uv_crop_width = src->uv_crop_width; |
137 | 0 | buf->img.uv_crop_height = src->uv_crop_height; |
138 | 0 | buf->img.subsampling_x = src->subsampling_x; |
139 | 0 | buf->img.subsampling_y = src->subsampling_y; |
140 | 0 | } |
141 | | // Partial copy not implemented yet |
142 | 1.26k | av1_copy_and_extend_frame(src, &buf->img); |
143 | | |
144 | 1.26k | buf->ts_start = ts_start; |
145 | 1.26k | buf->ts_end = ts_end; |
146 | 1.26k | buf->display_idx = ctx->push_frame_count; |
147 | 1.26k | buf->flags = flags; |
148 | 1.26k | ++ctx->push_frame_count; |
149 | 1.26k | aom_remove_metadata_from_frame_buffer(&buf->img); |
150 | 1.26k | aom_copy_metadata_to_frame_buffer(&buf->img, src->metadata); |
151 | 1.26k | return 0; |
152 | 1.26k | } |
153 | | |
154 | | struct lookahead_entry *av1_lookahead_pop(struct lookahead_ctx *ctx, int drain, |
155 | 1.26k | COMPRESSOR_STAGE stage) { |
156 | 1.26k | struct lookahead_entry *buf = NULL; |
157 | 1.26k | if (ctx) { |
158 | 1.26k | struct read_ctx *read_ctx = &ctx->read_ctxs[stage]; |
159 | 1.26k | assert(read_ctx->valid == 1); |
160 | 1.26k | if (read_ctx->sz && (drain || read_ctx->sz == read_ctx->pop_sz)) { |
161 | 1.26k | buf = pop(ctx, &read_ctx->read_idx); |
162 | 1.26k | read_ctx->sz--; |
163 | 1.26k | } |
164 | 1.26k | } |
165 | 1.26k | return buf; |
166 | 1.26k | } |
167 | | |
168 | | struct lookahead_entry *av1_lookahead_peek(struct lookahead_ctx *ctx, int index, |
169 | 6.31k | COMPRESSOR_STAGE stage) { |
170 | 6.31k | struct lookahead_entry *buf = NULL; |
171 | 6.31k | if (ctx == NULL) { |
172 | 0 | return buf; |
173 | 0 | } |
174 | | |
175 | 6.31k | struct read_ctx *read_ctx = &ctx->read_ctxs[stage]; |
176 | 6.31k | assert(read_ctx->valid == 1); |
177 | 6.31k | if (index >= 0) { |
178 | | // Forward peek |
179 | 6.31k | if (index < read_ctx->sz) { |
180 | 3.78k | index += read_ctx->read_idx; |
181 | 3.78k | if (index >= ctx->max_sz) index -= ctx->max_sz; |
182 | 3.78k | buf = ctx->buf + index; |
183 | 3.78k | } |
184 | 6.31k | } else if (index < 0) { |
185 | | // Backward peek |
186 | 0 | if (-index <= ctx->max_pre_frames) { |
187 | 0 | index += (int)(read_ctx->read_idx); |
188 | 0 | if (index < 0) index += (int)(ctx->max_sz); |
189 | 0 | buf = ctx->buf + index; |
190 | 0 | } |
191 | 0 | } |
192 | | |
193 | 6.31k | return buf; |
194 | 6.31k | } |
195 | | |
196 | | unsigned int av1_lookahead_depth(struct lookahead_ctx *ctx, |
197 | 5.04k | COMPRESSOR_STAGE stage) { |
198 | 5.04k | assert(ctx != NULL); |
199 | | |
200 | 5.04k | struct read_ctx *read_ctx = &ctx->read_ctxs[stage]; |
201 | 5.04k | assert(read_ctx->valid == 1); |
202 | 5.04k | return read_ctx->sz; |
203 | 5.04k | } |
204 | | |
205 | 5.04k | int av1_lookahead_pop_sz(struct lookahead_ctx *ctx, COMPRESSOR_STAGE stage) { |
206 | 5.04k | assert(ctx != NULL); |
207 | | |
208 | 5.04k | struct read_ctx *read_ctx = &ctx->read_ctxs[stage]; |
209 | 5.04k | assert(read_ctx->valid == 1); |
210 | 5.04k | return read_ctx->pop_sz; |
211 | 5.04k | } |