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