Line data Source code
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 "./aom_config.h"
15 :
16 : #include "av1/common/common.h"
17 :
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 : }
32 :
33 0 : void av1_lookahead_destroy(struct lookahead_ctx *ctx) {
34 0 : if (ctx) {
35 0 : if (ctx->buf) {
36 : 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 : }
41 0 : free(ctx);
42 : }
43 0 : }
44 :
45 0 : struct lookahead_ctx *av1_lookahead_init(unsigned int width,
46 : unsigned int height,
47 : unsigned int subsampling_x,
48 : unsigned int subsampling_y,
49 : #if CONFIG_HIGHBITDEPTH
50 : int use_highbitdepth,
51 : #endif
52 : unsigned int depth) {
53 0 : struct lookahead_ctx *ctx = NULL;
54 :
55 : // Clamp the lookahead queue depth
56 0 : depth = clamp(depth, 1, MAX_LAG_BUFFERS);
57 :
58 : // Allocate memory to keep previous source frames available.
59 0 : depth += MAX_PRE_FRAMES;
60 :
61 : // Allocate the lookahead structures
62 0 : ctx = calloc(1, sizeof(*ctx));
63 0 : if (ctx) {
64 0 : const int legacy_byte_alignment = 0;
65 : unsigned int i;
66 0 : ctx->max_sz = depth;
67 0 : ctx->buf = calloc(depth, sizeof(*ctx->buf));
68 0 : if (!ctx->buf) goto bail;
69 0 : for (i = 0; i < depth; i++)
70 0 : if (aom_alloc_frame_buffer(&ctx->buf[i].img, width, height, subsampling_x,
71 : subsampling_y,
72 : #if CONFIG_HIGHBITDEPTH
73 : use_highbitdepth,
74 : #endif
75 : AOM_BORDER_IN_PIXELS, legacy_byte_alignment))
76 0 : goto bail;
77 : }
78 0 : return ctx;
79 : bail:
80 0 : av1_lookahead_destroy(ctx);
81 0 : return NULL;
82 : }
83 :
84 : #define USE_PARTIAL_COPY 0
85 :
86 0 : int av1_lookahead_push(struct lookahead_ctx *ctx, YV12_BUFFER_CONFIG *src,
87 : int64_t ts_start, int64_t ts_end,
88 : #if CONFIG_HIGHBITDEPTH
89 : int use_highbitdepth,
90 : #endif
91 : aom_enc_frame_flags_t flags) {
92 : struct lookahead_entry *buf;
93 : #if USE_PARTIAL_COPY
94 : int row, col, active_end;
95 : int mb_rows = (src->y_height + 15) >> 4;
96 : int mb_cols = (src->y_width + 15) >> 4;
97 : #endif
98 0 : int width = src->y_crop_width;
99 0 : int height = src->y_crop_height;
100 0 : int uv_width = src->uv_crop_width;
101 0 : int uv_height = src->uv_crop_height;
102 0 : int subsampling_x = src->subsampling_x;
103 0 : int subsampling_y = src->subsampling_y;
104 : int larger_dimensions, new_dimensions;
105 :
106 0 : if (ctx->sz + 1 + MAX_PRE_FRAMES > ctx->max_sz) return 1;
107 0 : ctx->sz++;
108 0 : buf = pop(ctx, &ctx->write_idx);
109 :
110 0 : new_dimensions = width != buf->img.y_crop_width ||
111 0 : height != buf->img.y_crop_height ||
112 0 : uv_width != buf->img.uv_crop_width ||
113 0 : uv_height != buf->img.uv_crop_height;
114 0 : larger_dimensions = width > buf->img.y_width || height > buf->img.y_height ||
115 0 : uv_width > buf->img.uv_width ||
116 0 : uv_height > buf->img.uv_height;
117 0 : assert(!larger_dimensions || new_dimensions);
118 :
119 : #if USE_PARTIAL_COPY
120 : // TODO(jkoleszar): This is disabled for now, as
121 : // av1_copy_and_extend_frame_with_rect is not subsampling/alpha aware.
122 :
123 : // Only do this partial copy if the following conditions are all met:
124 : // 1. Lookahead queue has has size of 1.
125 : // 2. Active map is provided.
126 : // 3. This is not a key frame, golden nor altref frame.
127 : if (!new_dimensions && ctx->max_sz == 1 && active_map && !flags) {
128 : for (row = 0; row < mb_rows; ++row) {
129 : col = 0;
130 :
131 : while (1) {
132 : // Find the first active macroblock in this row.
133 : for (; col < mb_cols; ++col) {
134 : if (active_map[col]) break;
135 : }
136 :
137 : // No more active macroblock in this row.
138 : if (col == mb_cols) break;
139 :
140 : // Find the end of active region in this row.
141 : active_end = col;
142 :
143 : for (; active_end < mb_cols; ++active_end) {
144 : if (!active_map[active_end]) break;
145 : }
146 :
147 : // Only copy this active region.
148 : av1_copy_and_extend_frame_with_rect(src, &buf->img, row << 4, col << 4,
149 : 16, (active_end - col) << 4);
150 :
151 : // Start again from the end of this active region.
152 : col = active_end;
153 : }
154 :
155 : active_map += mb_cols;
156 : }
157 : } else {
158 : #endif
159 0 : if (larger_dimensions) {
160 : YV12_BUFFER_CONFIG new_img;
161 0 : memset(&new_img, 0, sizeof(new_img));
162 0 : if (aom_alloc_frame_buffer(&new_img, width, height, subsampling_x,
163 : subsampling_y,
164 : #if CONFIG_HIGHBITDEPTH
165 : use_highbitdepth,
166 : #endif
167 : AOM_BORDER_IN_PIXELS, 0))
168 0 : return 1;
169 0 : aom_free_frame_buffer(&buf->img);
170 0 : buf->img = new_img;
171 0 : } else if (new_dimensions) {
172 0 : buf->img.y_crop_width = src->y_crop_width;
173 0 : buf->img.y_crop_height = src->y_crop_height;
174 0 : buf->img.uv_crop_width = src->uv_crop_width;
175 0 : buf->img.uv_crop_height = src->uv_crop_height;
176 0 : buf->img.subsampling_x = src->subsampling_x;
177 0 : buf->img.subsampling_y = src->subsampling_y;
178 : }
179 : // Partial copy not implemented yet
180 0 : av1_copy_and_extend_frame(src, &buf->img);
181 : #if USE_PARTIAL_COPY
182 : }
183 : #endif
184 :
185 0 : buf->ts_start = ts_start;
186 0 : buf->ts_end = ts_end;
187 0 : buf->flags = flags;
188 0 : return 0;
189 : }
190 :
191 0 : struct lookahead_entry *av1_lookahead_pop(struct lookahead_ctx *ctx,
192 : int drain) {
193 0 : struct lookahead_entry *buf = NULL;
194 :
195 0 : if (ctx && ctx->sz && (drain || ctx->sz == ctx->max_sz - MAX_PRE_FRAMES)) {
196 0 : buf = pop(ctx, &ctx->read_idx);
197 0 : ctx->sz--;
198 : }
199 0 : return buf;
200 : }
201 :
202 0 : struct lookahead_entry *av1_lookahead_peek(struct lookahead_ctx *ctx,
203 : int index) {
204 0 : struct lookahead_entry *buf = NULL;
205 :
206 0 : if (index >= 0) {
207 : // Forward peek
208 0 : if (index < ctx->sz) {
209 0 : index += ctx->read_idx;
210 0 : if (index >= ctx->max_sz) index -= ctx->max_sz;
211 0 : buf = ctx->buf + index;
212 : }
213 0 : } else if (index < 0) {
214 : // Backward peek
215 0 : if (-index <= MAX_PRE_FRAMES) {
216 0 : index += (int)(ctx->read_idx);
217 0 : if (index < 0) index += (int)(ctx->max_sz);
218 0 : buf = ctx->buf + index;
219 : }
220 : }
221 :
222 0 : return buf;
223 : }
224 :
225 0 : unsigned int av1_lookahead_depth(struct lookahead_ctx *ctx) { return ctx->sz; }
|