xref: /aosp_15_r20/external/libvpx/vp8/encoder/lookahead.c (revision fb1b10ab9aebc7c7068eedab379b749d7e3900be)
1*fb1b10abSAndroid Build Coastguard Worker /*
2*fb1b10abSAndroid Build Coastguard Worker  *  Copyright (c) 2011 The WebM project authors. All Rights Reserved.
3*fb1b10abSAndroid Build Coastguard Worker  *
4*fb1b10abSAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*fb1b10abSAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*fb1b10abSAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*fb1b10abSAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*fb1b10abSAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*fb1b10abSAndroid Build Coastguard Worker  */
10*fb1b10abSAndroid Build Coastguard Worker #include <assert.h>
11*fb1b10abSAndroid Build Coastguard Worker #include <stdlib.h>
12*fb1b10abSAndroid Build Coastguard Worker #include "vpx_config.h"
13*fb1b10abSAndroid Build Coastguard Worker #include "lookahead.h"
14*fb1b10abSAndroid Build Coastguard Worker #include "vp8/common/extend.h"
15*fb1b10abSAndroid Build Coastguard Worker 
16*fb1b10abSAndroid Build Coastguard Worker #define MAX_LAG_BUFFERS (CONFIG_REALTIME_ONLY ? 1 : 25)
17*fb1b10abSAndroid Build Coastguard Worker 
18*fb1b10abSAndroid Build Coastguard Worker struct lookahead_ctx {
19*fb1b10abSAndroid Build Coastguard Worker   unsigned int max_sz;         /* Absolute size of the queue */
20*fb1b10abSAndroid Build Coastguard Worker   unsigned int sz;             /* Number of buffers currently in the queue */
21*fb1b10abSAndroid Build Coastguard Worker   unsigned int read_idx;       /* Read index */
22*fb1b10abSAndroid Build Coastguard Worker   unsigned int write_idx;      /* Write index */
23*fb1b10abSAndroid Build Coastguard Worker   struct lookahead_entry *buf; /* Buffer list */
24*fb1b10abSAndroid Build Coastguard Worker };
25*fb1b10abSAndroid Build Coastguard Worker 
26*fb1b10abSAndroid Build Coastguard Worker /* Return the buffer at the given absolute index and increment the index */
pop(struct lookahead_ctx * ctx,unsigned int * idx)27*fb1b10abSAndroid Build Coastguard Worker static struct lookahead_entry *pop(struct lookahead_ctx *ctx,
28*fb1b10abSAndroid Build Coastguard Worker                                    unsigned int *idx) {
29*fb1b10abSAndroid Build Coastguard Worker   unsigned int index = *idx;
30*fb1b10abSAndroid Build Coastguard Worker   struct lookahead_entry *buf = ctx->buf + index;
31*fb1b10abSAndroid Build Coastguard Worker 
32*fb1b10abSAndroid Build Coastguard Worker   assert(index < ctx->max_sz);
33*fb1b10abSAndroid Build Coastguard Worker   if (++index >= ctx->max_sz) index -= ctx->max_sz;
34*fb1b10abSAndroid Build Coastguard Worker   *idx = index;
35*fb1b10abSAndroid Build Coastguard Worker   return buf;
36*fb1b10abSAndroid Build Coastguard Worker }
37*fb1b10abSAndroid Build Coastguard Worker 
vp8_lookahead_destroy(struct lookahead_ctx * ctx)38*fb1b10abSAndroid Build Coastguard Worker void vp8_lookahead_destroy(struct lookahead_ctx *ctx) {
39*fb1b10abSAndroid Build Coastguard Worker   if (ctx) {
40*fb1b10abSAndroid Build Coastguard Worker     if (ctx->buf) {
41*fb1b10abSAndroid Build Coastguard Worker       unsigned int i;
42*fb1b10abSAndroid Build Coastguard Worker 
43*fb1b10abSAndroid Build Coastguard Worker       for (i = 0; i < ctx->max_sz; ++i) {
44*fb1b10abSAndroid Build Coastguard Worker         vp8_yv12_de_alloc_frame_buffer(&ctx->buf[i].img);
45*fb1b10abSAndroid Build Coastguard Worker       }
46*fb1b10abSAndroid Build Coastguard Worker       free(ctx->buf);
47*fb1b10abSAndroid Build Coastguard Worker     }
48*fb1b10abSAndroid Build Coastguard Worker     free(ctx);
49*fb1b10abSAndroid Build Coastguard Worker   }
50*fb1b10abSAndroid Build Coastguard Worker }
51*fb1b10abSAndroid Build Coastguard Worker 
vp8_lookahead_init(unsigned int width,unsigned int height,unsigned int depth)52*fb1b10abSAndroid Build Coastguard Worker struct lookahead_ctx *vp8_lookahead_init(unsigned int width,
53*fb1b10abSAndroid Build Coastguard Worker                                          unsigned int height,
54*fb1b10abSAndroid Build Coastguard Worker                                          unsigned int depth) {
55*fb1b10abSAndroid Build Coastguard Worker   struct lookahead_ctx *ctx = NULL;
56*fb1b10abSAndroid Build Coastguard Worker   unsigned int i;
57*fb1b10abSAndroid Build Coastguard Worker 
58*fb1b10abSAndroid Build Coastguard Worker   /* Clamp the lookahead queue depth */
59*fb1b10abSAndroid Build Coastguard Worker   if (depth < 1) {
60*fb1b10abSAndroid Build Coastguard Worker     depth = 1;
61*fb1b10abSAndroid Build Coastguard Worker   } else if (depth > MAX_LAG_BUFFERS) {
62*fb1b10abSAndroid Build Coastguard Worker     depth = MAX_LAG_BUFFERS;
63*fb1b10abSAndroid Build Coastguard Worker   }
64*fb1b10abSAndroid Build Coastguard Worker 
65*fb1b10abSAndroid Build Coastguard Worker   /* Keep last frame in lookahead buffer by increasing depth by 1.*/
66*fb1b10abSAndroid Build Coastguard Worker   depth += 1;
67*fb1b10abSAndroid Build Coastguard Worker 
68*fb1b10abSAndroid Build Coastguard Worker   /* Align the buffer dimensions */
69*fb1b10abSAndroid Build Coastguard Worker   width = (width + 15) & ~15u;
70*fb1b10abSAndroid Build Coastguard Worker   height = (height + 15) & ~15u;
71*fb1b10abSAndroid Build Coastguard Worker 
72*fb1b10abSAndroid Build Coastguard Worker   /* Allocate the lookahead structures */
73*fb1b10abSAndroid Build Coastguard Worker   ctx = calloc(1, sizeof(*ctx));
74*fb1b10abSAndroid Build Coastguard Worker   if (ctx) {
75*fb1b10abSAndroid Build Coastguard Worker     ctx->max_sz = depth;
76*fb1b10abSAndroid Build Coastguard Worker     ctx->buf = calloc(depth, sizeof(*ctx->buf));
77*fb1b10abSAndroid Build Coastguard Worker     if (!ctx->buf) goto bail;
78*fb1b10abSAndroid Build Coastguard Worker     for (i = 0; i < depth; ++i) {
79*fb1b10abSAndroid Build Coastguard Worker       if (vp8_yv12_alloc_frame_buffer(&ctx->buf[i].img, width, height,
80*fb1b10abSAndroid Build Coastguard Worker                                       VP8BORDERINPIXELS)) {
81*fb1b10abSAndroid Build Coastguard Worker         goto bail;
82*fb1b10abSAndroid Build Coastguard Worker       }
83*fb1b10abSAndroid Build Coastguard Worker     }
84*fb1b10abSAndroid Build Coastguard Worker   }
85*fb1b10abSAndroid Build Coastguard Worker   return ctx;
86*fb1b10abSAndroid Build Coastguard Worker bail:
87*fb1b10abSAndroid Build Coastguard Worker   vp8_lookahead_destroy(ctx);
88*fb1b10abSAndroid Build Coastguard Worker   return NULL;
89*fb1b10abSAndroid Build Coastguard Worker }
90*fb1b10abSAndroid Build Coastguard Worker 
vp8_lookahead_push(struct lookahead_ctx * ctx,YV12_BUFFER_CONFIG * src,int64_t ts_start,int64_t ts_end,unsigned int flags,unsigned char * active_map)91*fb1b10abSAndroid Build Coastguard Worker int vp8_lookahead_push(struct lookahead_ctx *ctx, YV12_BUFFER_CONFIG *src,
92*fb1b10abSAndroid Build Coastguard Worker                        int64_t ts_start, int64_t ts_end, unsigned int flags,
93*fb1b10abSAndroid Build Coastguard Worker                        unsigned char *active_map) {
94*fb1b10abSAndroid Build Coastguard Worker   struct lookahead_entry *buf;
95*fb1b10abSAndroid Build Coastguard Worker   int row, col, active_end;
96*fb1b10abSAndroid Build Coastguard Worker   int mb_rows = (src->y_height + 15) >> 4;
97*fb1b10abSAndroid Build Coastguard Worker   int mb_cols = (src->y_width + 15) >> 4;
98*fb1b10abSAndroid Build Coastguard Worker 
99*fb1b10abSAndroid Build Coastguard Worker   if (ctx->sz + 2 > ctx->max_sz) return 1;
100*fb1b10abSAndroid Build Coastguard Worker   ctx->sz++;
101*fb1b10abSAndroid Build Coastguard Worker   buf = pop(ctx, &ctx->write_idx);
102*fb1b10abSAndroid Build Coastguard Worker 
103*fb1b10abSAndroid Build Coastguard Worker   /* Only do this partial copy if the following conditions are all met:
104*fb1b10abSAndroid Build Coastguard Worker    * 1. Lookahead queue has has size of 1.
105*fb1b10abSAndroid Build Coastguard Worker    * 2. Active map is provided.
106*fb1b10abSAndroid Build Coastguard Worker    * 3. This is not a key frame, golden nor altref frame.
107*fb1b10abSAndroid Build Coastguard Worker    */
108*fb1b10abSAndroid Build Coastguard Worker   if (ctx->max_sz == 1 && active_map && !flags) {
109*fb1b10abSAndroid Build Coastguard Worker     for (row = 0; row < mb_rows; ++row) {
110*fb1b10abSAndroid Build Coastguard Worker       col = 0;
111*fb1b10abSAndroid Build Coastguard Worker 
112*fb1b10abSAndroid Build Coastguard Worker       while (1) {
113*fb1b10abSAndroid Build Coastguard Worker         /* Find the first active macroblock in this row. */
114*fb1b10abSAndroid Build Coastguard Worker         for (; col < mb_cols; ++col) {
115*fb1b10abSAndroid Build Coastguard Worker           if (active_map[col]) break;
116*fb1b10abSAndroid Build Coastguard Worker         }
117*fb1b10abSAndroid Build Coastguard Worker 
118*fb1b10abSAndroid Build Coastguard Worker         /* No more active macroblock in this row. */
119*fb1b10abSAndroid Build Coastguard Worker         if (col == mb_cols) break;
120*fb1b10abSAndroid Build Coastguard Worker 
121*fb1b10abSAndroid Build Coastguard Worker         /* Find the end of active region in this row. */
122*fb1b10abSAndroid Build Coastguard Worker         active_end = col;
123*fb1b10abSAndroid Build Coastguard Worker 
124*fb1b10abSAndroid Build Coastguard Worker         for (; active_end < mb_cols; ++active_end) {
125*fb1b10abSAndroid Build Coastguard Worker           if (!active_map[active_end]) break;
126*fb1b10abSAndroid Build Coastguard Worker         }
127*fb1b10abSAndroid Build Coastguard Worker 
128*fb1b10abSAndroid Build Coastguard Worker         /* Only copy this active region. */
129*fb1b10abSAndroid Build Coastguard Worker         vp8_copy_and_extend_frame_with_rect(src, &buf->img, row << 4, col << 4,
130*fb1b10abSAndroid Build Coastguard Worker                                             16, (active_end - col) << 4);
131*fb1b10abSAndroid Build Coastguard Worker 
132*fb1b10abSAndroid Build Coastguard Worker         /* Start again from the end of this active region. */
133*fb1b10abSAndroid Build Coastguard Worker         col = active_end;
134*fb1b10abSAndroid Build Coastguard Worker       }
135*fb1b10abSAndroid Build Coastguard Worker 
136*fb1b10abSAndroid Build Coastguard Worker       active_map += mb_cols;
137*fb1b10abSAndroid Build Coastguard Worker     }
138*fb1b10abSAndroid Build Coastguard Worker   } else {
139*fb1b10abSAndroid Build Coastguard Worker     vp8_copy_and_extend_frame(src, &buf->img);
140*fb1b10abSAndroid Build Coastguard Worker   }
141*fb1b10abSAndroid Build Coastguard Worker   buf->ts_start = ts_start;
142*fb1b10abSAndroid Build Coastguard Worker   buf->ts_end = ts_end;
143*fb1b10abSAndroid Build Coastguard Worker   buf->flags = flags;
144*fb1b10abSAndroid Build Coastguard Worker   return 0;
145*fb1b10abSAndroid Build Coastguard Worker }
146*fb1b10abSAndroid Build Coastguard Worker 
vp8_lookahead_pop(struct lookahead_ctx * ctx,int drain)147*fb1b10abSAndroid Build Coastguard Worker struct lookahead_entry *vp8_lookahead_pop(struct lookahead_ctx *ctx,
148*fb1b10abSAndroid Build Coastguard Worker                                           int drain) {
149*fb1b10abSAndroid Build Coastguard Worker   struct lookahead_entry *buf = NULL;
150*fb1b10abSAndroid Build Coastguard Worker 
151*fb1b10abSAndroid Build Coastguard Worker   assert(ctx != NULL);
152*fb1b10abSAndroid Build Coastguard Worker   if (ctx->sz && (drain || ctx->sz == ctx->max_sz - 1)) {
153*fb1b10abSAndroid Build Coastguard Worker     buf = pop(ctx, &ctx->read_idx);
154*fb1b10abSAndroid Build Coastguard Worker     ctx->sz--;
155*fb1b10abSAndroid Build Coastguard Worker   }
156*fb1b10abSAndroid Build Coastguard Worker   return buf;
157*fb1b10abSAndroid Build Coastguard Worker }
158*fb1b10abSAndroid Build Coastguard Worker 
vp8_lookahead_peek(struct lookahead_ctx * ctx,unsigned int index,int direction)159*fb1b10abSAndroid Build Coastguard Worker struct lookahead_entry *vp8_lookahead_peek(struct lookahead_ctx *ctx,
160*fb1b10abSAndroid Build Coastguard Worker                                            unsigned int index, int direction) {
161*fb1b10abSAndroid Build Coastguard Worker   struct lookahead_entry *buf = NULL;
162*fb1b10abSAndroid Build Coastguard Worker 
163*fb1b10abSAndroid Build Coastguard Worker   if (direction == PEEK_FORWARD) {
164*fb1b10abSAndroid Build Coastguard Worker     assert(index < ctx->max_sz - 1);
165*fb1b10abSAndroid Build Coastguard Worker     if (index < ctx->sz) {
166*fb1b10abSAndroid Build Coastguard Worker       index += ctx->read_idx;
167*fb1b10abSAndroid Build Coastguard Worker       if (index >= ctx->max_sz) index -= ctx->max_sz;
168*fb1b10abSAndroid Build Coastguard Worker       buf = ctx->buf + index;
169*fb1b10abSAndroid Build Coastguard Worker     }
170*fb1b10abSAndroid Build Coastguard Worker   } else if (direction == PEEK_BACKWARD) {
171*fb1b10abSAndroid Build Coastguard Worker     assert(index == 1);
172*fb1b10abSAndroid Build Coastguard Worker 
173*fb1b10abSAndroid Build Coastguard Worker     if (ctx->read_idx == 0) {
174*fb1b10abSAndroid Build Coastguard Worker       index = ctx->max_sz - 1;
175*fb1b10abSAndroid Build Coastguard Worker     } else {
176*fb1b10abSAndroid Build Coastguard Worker       index = ctx->read_idx - index;
177*fb1b10abSAndroid Build Coastguard Worker     }
178*fb1b10abSAndroid Build Coastguard Worker     buf = ctx->buf + index;
179*fb1b10abSAndroid Build Coastguard Worker   }
180*fb1b10abSAndroid Build Coastguard Worker 
181*fb1b10abSAndroid Build Coastguard Worker   return buf;
182*fb1b10abSAndroid Build Coastguard Worker }
183*fb1b10abSAndroid Build Coastguard Worker 
vp8_lookahead_depth(struct lookahead_ctx * ctx)184*fb1b10abSAndroid Build Coastguard Worker unsigned int vp8_lookahead_depth(struct lookahead_ctx *ctx) { return ctx->sz; }
185