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