ffmpeg / libavcodec / qtrleenc.c @ d36beb3f
History | View | Annotate | Download (11.1 KB)
1 |
/*
|
---|---|
2 |
* Quicktime Animation (RLE) Video Encoder
|
3 |
* Copyright (C) 2007 Clemens Fruhwirth
|
4 |
* Copyright (C) 2007 Alexis Ballier
|
5 |
*
|
6 |
* This file is based on flashsvenc.c.
|
7 |
*
|
8 |
* This file is part of FFmpeg.
|
9 |
*
|
10 |
* FFmpeg is free software; you can redistribute it and/or
|
11 |
* modify it under the terms of the GNU Lesser General Public
|
12 |
* License as published by the Free Software Foundation; either
|
13 |
* version 2.1 of the License, or (at your option) any later version.
|
14 |
*
|
15 |
* FFmpeg is distributed in the hope that it will be useful,
|
16 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
17 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
18 |
* Lesser General Public License for more details.
|
19 |
*
|
20 |
* You should have received a copy of the GNU Lesser General Public
|
21 |
* License along with FFmpeg; if not, write to the Free Software
|
22 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
23 |
*/
|
24 |
|
25 |
#include "libavcore/imgutils.h" |
26 |
#include "avcodec.h" |
27 |
#include "bytestream.h" |
28 |
|
29 |
/** Maximum RLE code for bulk copy */
|
30 |
#define MAX_RLE_BULK 127 |
31 |
/** Maximum RLE code for repeat */
|
32 |
#define MAX_RLE_REPEAT 128 |
33 |
/** Maximum RLE code for skip */
|
34 |
#define MAX_RLE_SKIP 254 |
35 |
|
36 |
typedef struct QtrleEncContext { |
37 |
AVCodecContext *avctx; |
38 |
AVFrame frame; |
39 |
int pixel_size;
|
40 |
AVPicture previous_frame; |
41 |
unsigned int max_buf_size; |
42 |
/**
|
43 |
* This array will contain at ith position the value of the best RLE code
|
44 |
* if the line started at pixel i
|
45 |
* There can be 3 values :
|
46 |
* skip (0) : skip as much as possible pixels because they are equal to the
|
47 |
* previous frame ones
|
48 |
* repeat (<-1) : repeat that pixel -rle_code times, still as much as
|
49 |
* possible
|
50 |
* copy (>0) : copy the raw next rle_code pixels */
|
51 |
signed char *rlecode_table; |
52 |
/**
|
53 |
* This array will contain the length of the best rle encoding of the line
|
54 |
* starting at ith pixel */
|
55 |
int *length_table;
|
56 |
/**
|
57 |
* Will contain at ith position the number of consecutive pixels equal to the previous
|
58 |
* frame starting from pixel i */
|
59 |
uint8_t* skip_table; |
60 |
} QtrleEncContext; |
61 |
|
62 |
static av_cold int qtrle_encode_init(AVCodecContext *avctx) |
63 |
{ |
64 |
QtrleEncContext *s = avctx->priv_data; |
65 |
|
66 |
if (av_image_check_size(avctx->width, avctx->height, 0, avctx) < 0) { |
67 |
return -1; |
68 |
} |
69 |
s->avctx=avctx; |
70 |
|
71 |
switch (avctx->pix_fmt) {
|
72 |
case PIX_FMT_RGB555BE:
|
73 |
s->pixel_size = 2;
|
74 |
break;
|
75 |
case PIX_FMT_RGB24:
|
76 |
s->pixel_size = 3;
|
77 |
break;
|
78 |
case PIX_FMT_ARGB:
|
79 |
s->pixel_size = 4;
|
80 |
break;
|
81 |
default:
|
82 |
av_log(avctx, AV_LOG_ERROR, "Unsupported colorspace.\n");
|
83 |
break;
|
84 |
} |
85 |
avctx->bits_per_coded_sample = s->pixel_size*8;
|
86 |
|
87 |
s->rlecode_table = av_mallocz(s->avctx->width); |
88 |
s->skip_table = av_mallocz(s->avctx->width); |
89 |
s->length_table = av_mallocz((s->avctx->width + 1)*sizeof(int)); |
90 |
if (!s->skip_table || !s->length_table || !s->rlecode_table) {
|
91 |
av_log(avctx, AV_LOG_ERROR, "Error allocating memory.\n");
|
92 |
return -1; |
93 |
} |
94 |
if (avpicture_alloc(&s->previous_frame, avctx->pix_fmt, avctx->width, avctx->height) < 0) { |
95 |
av_log(avctx, AV_LOG_ERROR, "Error allocating picture\n");
|
96 |
return -1; |
97 |
} |
98 |
|
99 |
s->max_buf_size = s->avctx->width*s->avctx->height*s->pixel_size /* image base material */
|
100 |
+ 15 /* header + footer */ |
101 |
+ s->avctx->height*2 /* skip code+rle end */ |
102 |
+ s->avctx->width/MAX_RLE_BULK + 1 /* rle codes */; |
103 |
avctx->coded_frame = &s->frame; |
104 |
return 0; |
105 |
} |
106 |
|
107 |
/**
|
108 |
* Compute the best RLE sequence for a line
|
109 |
*/
|
110 |
static void qtrle_encode_line(QtrleEncContext *s, AVFrame *p, int line, uint8_t **buf) |
111 |
{ |
112 |
int width=s->avctx->width;
|
113 |
int i;
|
114 |
signed char rlecode; |
115 |
|
116 |
/* We will use it to compute the best bulk copy sequence */
|
117 |
unsigned int bulkcount; |
118 |
/* This will be the number of pixels equal to the preivous frame one's
|
119 |
* starting from the ith pixel */
|
120 |
unsigned int skipcount; |
121 |
/* This will be the number of consecutive equal pixels in the current
|
122 |
* frame, starting from the ith one also */
|
123 |
unsigned int av_uninit(repeatcount); |
124 |
|
125 |
/* The cost of the three different possibilities */
|
126 |
int total_bulk_cost;
|
127 |
int total_skip_cost;
|
128 |
int total_repeat_cost;
|
129 |
|
130 |
int temp_cost;
|
131 |
int j;
|
132 |
|
133 |
uint8_t *this_line = p-> data[0] + line*p-> linesize[0] + |
134 |
(width - 1)*s->pixel_size;
|
135 |
uint8_t *prev_line = s->previous_frame.data[0] + line*s->previous_frame.linesize[0] + |
136 |
(width - 1)*s->pixel_size;
|
137 |
|
138 |
s->length_table[width] = 0;
|
139 |
skipcount = 0;
|
140 |
|
141 |
for (i = width - 1; i >= 0; i--) { |
142 |
|
143 |
if (!s->frame.key_frame && !memcmp(this_line, prev_line, s->pixel_size))
|
144 |
skipcount = FFMIN(skipcount + 1, MAX_RLE_SKIP);
|
145 |
else
|
146 |
skipcount = 0;
|
147 |
|
148 |
total_skip_cost = s->length_table[i + skipcount] + 2;
|
149 |
s->skip_table[i] = skipcount; |
150 |
|
151 |
|
152 |
if (i < width - 1 && !memcmp(this_line, this_line + s->pixel_size, s->pixel_size)) |
153 |
repeatcount = FFMIN(repeatcount + 1, MAX_RLE_REPEAT);
|
154 |
else
|
155 |
repeatcount = 1;
|
156 |
|
157 |
total_repeat_cost = s->length_table[i + repeatcount] + 1 + s->pixel_size;
|
158 |
|
159 |
/* skip code is free for the first pixel, it costs one byte for repeat and bulk copy
|
160 |
* so let's make it aware */
|
161 |
if (i == 0) { |
162 |
total_skip_cost--; |
163 |
total_repeat_cost++; |
164 |
} |
165 |
|
166 |
if (repeatcount > 1 && (skipcount == 0 || total_repeat_cost < total_skip_cost)) { |
167 |
/* repeat is the best */
|
168 |
s->length_table[i] = total_repeat_cost; |
169 |
s->rlecode_table[i] = -repeatcount; |
170 |
} |
171 |
else if (skipcount > 0) { |
172 |
/* skip is the best choice here */
|
173 |
s->length_table[i] = total_skip_cost; |
174 |
s->rlecode_table[i] = 0;
|
175 |
} |
176 |
else {
|
177 |
/* We cannot do neither skip nor repeat
|
178 |
* thus we search for the best bulk copy to do */
|
179 |
|
180 |
int limit = FFMIN(width - i, MAX_RLE_BULK);
|
181 |
|
182 |
temp_cost = 1 + s->pixel_size + !i;
|
183 |
total_bulk_cost = INT_MAX; |
184 |
|
185 |
for (j = 1; j <= limit; j++) { |
186 |
if (s->length_table[i + j] + temp_cost < total_bulk_cost) {
|
187 |
/* We have found a better bulk copy ... */
|
188 |
total_bulk_cost = s->length_table[i + j] + temp_cost; |
189 |
bulkcount = j; |
190 |
} |
191 |
temp_cost += s->pixel_size; |
192 |
} |
193 |
|
194 |
s->length_table[i] = total_bulk_cost; |
195 |
s->rlecode_table[i] = bulkcount; |
196 |
} |
197 |
|
198 |
this_line -= s->pixel_size; |
199 |
prev_line -= s->pixel_size; |
200 |
} |
201 |
|
202 |
/* Good ! Now we have the best sequence for this line, let's ouput it */
|
203 |
|
204 |
/* We do a special case for the first pixel so that we avoid testing it in
|
205 |
* the whole loop */
|
206 |
|
207 |
i=0;
|
208 |
this_line = p-> data[0] + line*p->linesize[0]; |
209 |
|
210 |
if (s->rlecode_table[0] == 0) { |
211 |
bytestream_put_byte(buf, s->skip_table[0] + 1); |
212 |
i += s->skip_table[0];
|
213 |
} |
214 |
else bytestream_put_byte(buf, 1); |
215 |
|
216 |
|
217 |
while (i < width) {
|
218 |
rlecode = s->rlecode_table[i]; |
219 |
bytestream_put_byte(buf, rlecode); |
220 |
if (rlecode == 0) { |
221 |
/* Write a skip sequence */
|
222 |
bytestream_put_byte(buf, s->skip_table[i] + 1);
|
223 |
i += s->skip_table[i]; |
224 |
} |
225 |
else if (rlecode > 0) { |
226 |
/* bulk copy */
|
227 |
bytestream_put_buffer(buf, this_line + i*s->pixel_size, rlecode*s->pixel_size); |
228 |
i += rlecode; |
229 |
} |
230 |
else {
|
231 |
/* repeat the bits */
|
232 |
bytestream_put_buffer(buf, this_line + i*s->pixel_size, s->pixel_size); |
233 |
i -= rlecode; |
234 |
} |
235 |
} |
236 |
bytestream_put_byte(buf, -1); // end RLE line |
237 |
} |
238 |
|
239 |
/** Encode frame including header */
|
240 |
static int encode_frame(QtrleEncContext *s, AVFrame *p, uint8_t *buf) |
241 |
{ |
242 |
int i;
|
243 |
int start_line = 0; |
244 |
int end_line = s->avctx->height;
|
245 |
uint8_t *orig_buf = buf; |
246 |
|
247 |
if (!s->frame.key_frame) {
|
248 |
unsigned line_size = s->avctx->width * s->pixel_size;
|
249 |
for (start_line = 0; start_line < s->avctx->height; start_line++) |
250 |
if (memcmp(p->data[0] + start_line*p->linesize[0], |
251 |
s->previous_frame.data[0] + start_line*s->previous_frame.linesize[0], |
252 |
line_size)) |
253 |
break;
|
254 |
|
255 |
for (end_line=s->avctx->height; end_line > start_line; end_line--)
|
256 |
if (memcmp(p->data[0] + (end_line - 1)*p->linesize[0], |
257 |
s->previous_frame.data[0] + (end_line - 1)*s->previous_frame.linesize[0], |
258 |
line_size)) |
259 |
break;
|
260 |
} |
261 |
|
262 |
bytestream_put_be32(&buf, 0); // CHUNK SIZE, patched later |
263 |
|
264 |
if ((start_line == 0 && end_line == s->avctx->height) || start_line == s->avctx->height) |
265 |
bytestream_put_be16(&buf, 0); // header |
266 |
else {
|
267 |
bytestream_put_be16(&buf, 8); // header |
268 |
bytestream_put_be16(&buf, start_line); // starting line
|
269 |
bytestream_put_be16(&buf, 0); // unknown |
270 |
bytestream_put_be16(&buf, end_line - start_line); // lines to update
|
271 |
bytestream_put_be16(&buf, 0); // unknown |
272 |
} |
273 |
for (i = start_line; i < end_line; i++)
|
274 |
qtrle_encode_line(s, p, i, &buf); |
275 |
|
276 |
bytestream_put_byte(&buf, 0); // zero skip code = frame finished |
277 |
AV_WB32(orig_buf, buf - orig_buf); // patch the chunk size
|
278 |
return buf - orig_buf;
|
279 |
} |
280 |
|
281 |
static int qtrle_encode_frame(AVCodecContext *avctx, uint8_t *buf, int buf_size, void *data) |
282 |
{ |
283 |
QtrleEncContext * const s = avctx->priv_data;
|
284 |
AVFrame *pict = data; |
285 |
AVFrame * const p = &s->frame;
|
286 |
int chunksize;
|
287 |
|
288 |
*p = *pict; |
289 |
|
290 |
if (buf_size < s->max_buf_size) {
|
291 |
/* Upper bound check for compressed data */
|
292 |
av_log(avctx, AV_LOG_ERROR, "buf_size %d < %d\n", buf_size, s->max_buf_size);
|
293 |
return -1; |
294 |
} |
295 |
|
296 |
if (avctx->gop_size == 0 || (s->avctx->frame_number % avctx->gop_size) == 0) { |
297 |
/* I-Frame */
|
298 |
p->pict_type = FF_I_TYPE; |
299 |
p->key_frame = 1;
|
300 |
} else {
|
301 |
/* P-Frame */
|
302 |
p->pict_type = FF_P_TYPE; |
303 |
p->key_frame = 0;
|
304 |
} |
305 |
|
306 |
chunksize = encode_frame(s, pict, buf); |
307 |
|
308 |
/* save the current frame */
|
309 |
av_picture_copy(&s->previous_frame, (AVPicture *)p, avctx->pix_fmt, avctx->width, avctx->height); |
310 |
return chunksize;
|
311 |
} |
312 |
|
313 |
static av_cold int qtrle_encode_end(AVCodecContext *avctx) |
314 |
{ |
315 |
QtrleEncContext *s = avctx->priv_data; |
316 |
|
317 |
avpicture_free(&s->previous_frame); |
318 |
av_free(s->rlecode_table); |
319 |
av_free(s->length_table); |
320 |
av_free(s->skip_table); |
321 |
return 0; |
322 |
} |
323 |
|
324 |
AVCodec ff_qtrle_encoder = { |
325 |
"qtrle",
|
326 |
AVMEDIA_TYPE_VIDEO, |
327 |
CODEC_ID_QTRLE, |
328 |
sizeof(QtrleEncContext),
|
329 |
qtrle_encode_init, |
330 |
qtrle_encode_frame, |
331 |
qtrle_encode_end, |
332 |
.pix_fmts = (const enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_RGB555BE, PIX_FMT_ARGB, PIX_FMT_NONE}, |
333 |
.long_name = NULL_IF_CONFIG_SMALL("QuickTime Animation (RLE) video"),
|
334 |
}; |