/src/ffmpeg/libavcodec/qtrleenc.c
Line | Count | Source (jump to first uncovered line) |
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 "libavutil/imgutils.h" |
26 | | #include "libavutil/mem.h" |
27 | | #include "avcodec.h" |
28 | | #include "bytestream.h" |
29 | | #include "codec_internal.h" |
30 | | #include "encode.h" |
31 | | |
32 | | /** Maximum RLE code for bulk copy */ |
33 | 559 | #define MAX_RLE_BULK 127 |
34 | | /** Maximum RLE code for repeat */ |
35 | | #define MAX_RLE_REPEAT 128 |
36 | | /** Maximum RLE code for skip */ |
37 | | #define MAX_RLE_SKIP 254 |
38 | | |
39 | | typedef struct QtrleEncContext { |
40 | | AVCodecContext *avctx; |
41 | | int pixel_size; |
42 | | AVFrame *previous_frame; |
43 | | unsigned int max_buf_size; |
44 | | int logical_width; |
45 | | /** |
46 | | * This array will contain at ith position the value of the best RLE code |
47 | | * if the line started at pixel i |
48 | | * There can be 3 values : |
49 | | * skip (0) : skip as much as possible pixels because they are equal to the |
50 | | * previous frame ones |
51 | | * repeat (<-1) : repeat that pixel -rle_code times, still as much as |
52 | | * possible |
53 | | * copy (>0) : copy the raw next rle_code pixels */ |
54 | | signed char *rlecode_table; |
55 | | /** |
56 | | * This array will contain the length of the best rle encoding of the line |
57 | | * starting at ith pixel */ |
58 | | int *length_table; |
59 | | /** |
60 | | * Will contain at ith position the number of consecutive pixels equal to the previous |
61 | | * frame starting from pixel i */ |
62 | | uint8_t* skip_table; |
63 | | |
64 | | /** Encoded frame is a key frame */ |
65 | | int key_frame; |
66 | | } QtrleEncContext; |
67 | | |
68 | | static av_cold int qtrle_encode_end(AVCodecContext *avctx) |
69 | 561 | { |
70 | 561 | QtrleEncContext *s = avctx->priv_data; |
71 | | |
72 | 561 | av_frame_free(&s->previous_frame); |
73 | 561 | av_free(s->rlecode_table); |
74 | 561 | av_free(s->length_table); |
75 | 561 | av_free(s->skip_table); |
76 | 561 | return 0; |
77 | 561 | } |
78 | | |
79 | | static av_cold int qtrle_encode_init(AVCodecContext *avctx) |
80 | 561 | { |
81 | 561 | QtrleEncContext *s = avctx->priv_data; |
82 | | |
83 | 561 | if (av_image_check_size(avctx->width, avctx->height, 0, avctx) < 0) { |
84 | 0 | return AVERROR(EINVAL); |
85 | 0 | } |
86 | 561 | s->avctx=avctx; |
87 | 561 | s->logical_width=avctx->width; |
88 | | |
89 | 561 | switch (avctx->pix_fmt) { |
90 | 96 | case AV_PIX_FMT_GRAY8: |
91 | 96 | if (avctx->width % 4) { |
92 | 2 | av_log(avctx, AV_LOG_ERROR, "Width not being a multiple of 4 is not supported\n"); |
93 | 2 | return AVERROR(EINVAL); |
94 | 2 | } |
95 | 94 | s->logical_width = avctx->width / 4; |
96 | 94 | s->pixel_size = 4; |
97 | 94 | break; |
98 | 122 | case AV_PIX_FMT_RGB555BE: |
99 | 122 | s->pixel_size = 2; |
100 | 122 | break; |
101 | 150 | case AV_PIX_FMT_RGB24: |
102 | 150 | s->pixel_size = 3; |
103 | 150 | break; |
104 | 193 | case AV_PIX_FMT_ARGB: |
105 | 193 | s->pixel_size = 4; |
106 | 193 | break; |
107 | 0 | default: |
108 | 0 | av_log(avctx, AV_LOG_ERROR, "Unsupported colorspace.\n"); |
109 | 0 | break; |
110 | 561 | } |
111 | 559 | avctx->bits_per_coded_sample = avctx->pix_fmt == AV_PIX_FMT_GRAY8 ? 40 : s->pixel_size*8; |
112 | | |
113 | 559 | s->rlecode_table = av_mallocz(s->logical_width); |
114 | 559 | s->skip_table = av_mallocz(s->logical_width); |
115 | 559 | s->length_table = av_calloc(s->logical_width + 1, sizeof(*s->length_table)); |
116 | 559 | if (!s->skip_table || !s->length_table || !s->rlecode_table) { |
117 | 0 | av_log(avctx, AV_LOG_ERROR, "Error allocating memory.\n"); |
118 | 0 | return AVERROR(ENOMEM); |
119 | 0 | } |
120 | 559 | s->previous_frame = av_frame_alloc(); |
121 | 559 | if (!s->previous_frame) { |
122 | 0 | av_log(avctx, AV_LOG_ERROR, "Error allocating picture\n"); |
123 | 0 | return AVERROR(ENOMEM); |
124 | 0 | } |
125 | | |
126 | 559 | s->max_buf_size = s->logical_width*s->avctx->height*s->pixel_size*2 /* image base material */ |
127 | 559 | + 15 /* header + footer */ |
128 | 559 | + s->avctx->height*2 /* skip code+rle end */ |
129 | 559 | + s->logical_width/MAX_RLE_BULK + 1 /* rle codes */; |
130 | | |
131 | 559 | return 0; |
132 | 559 | } |
133 | | |
134 | | /** |
135 | | * Compute the best RLE sequence for a line |
136 | | */ |
137 | | static void qtrle_encode_line(QtrleEncContext *s, const AVFrame *p, int line, uint8_t **buf) |
138 | 1.85M | { |
139 | 1.85M | int width=s->logical_width; |
140 | 1.85M | int i; |
141 | 1.85M | signed char rlecode; |
142 | | |
143 | | /* This will be the number of pixels equal to the previous frame one's |
144 | | * starting from the ith pixel */ |
145 | 1.85M | unsigned int skipcount; |
146 | | /* This will be the number of consecutive equal pixels in the current |
147 | | * frame, starting from the ith one also */ |
148 | 1.85M | unsigned int av_uninit(repeatcount); |
149 | | |
150 | | /* The cost of the three different possibilities */ |
151 | 1.85M | int total_skip_cost; |
152 | 1.85M | int total_repeat_cost; |
153 | | |
154 | 1.85M | int base_bulk_cost; |
155 | 1.85M | int lowest_bulk_cost; |
156 | 1.85M | int lowest_bulk_cost_index; |
157 | 1.85M | int sec_lowest_bulk_cost; |
158 | 1.85M | int sec_lowest_bulk_cost_index; |
159 | | |
160 | 1.85M | const uint8_t *this_line = p->data[0] + line * p->linesize[0] + width * s->pixel_size; |
161 | | /* There might be no earlier frame if the current frame is a keyframe. |
162 | | * So just use a pointer to the current frame to avoid a check |
163 | | * to avoid NULL - s->pixel_size (which is undefined behaviour). */ |
164 | 1.85M | const uint8_t *prev_line = s->key_frame ? this_line |
165 | 1.85M | : s->previous_frame->data[0] |
166 | 103k | + line * s->previous_frame->linesize[0] |
167 | 103k | + width * s->pixel_size; |
168 | | |
169 | 1.85M | s->length_table[width] = 0; |
170 | 1.85M | skipcount = 0; |
171 | | |
172 | | /* Initial values */ |
173 | 1.85M | lowest_bulk_cost = INT_MAX / 2; |
174 | 1.85M | lowest_bulk_cost_index = width; |
175 | 1.85M | sec_lowest_bulk_cost = INT_MAX / 2; |
176 | 1.85M | sec_lowest_bulk_cost_index = width; |
177 | | |
178 | 1.85M | base_bulk_cost = 1 + s->pixel_size; |
179 | | |
180 | 15.5M | for (i = width - 1; i >= 0; i--) { |
181 | | |
182 | 13.7M | int prev_bulk_cost; |
183 | | |
184 | 13.7M | this_line -= s->pixel_size; |
185 | 13.7M | prev_line -= s->pixel_size; |
186 | | |
187 | | /* If our lowest bulk cost index is too far away, replace it |
188 | | * with the next lowest bulk cost */ |
189 | 13.7M | if (FFMIN(width, i + MAX_RLE_BULK) < lowest_bulk_cost_index) { |
190 | 1.54k | lowest_bulk_cost = sec_lowest_bulk_cost; |
191 | 1.54k | lowest_bulk_cost_index = sec_lowest_bulk_cost_index; |
192 | | |
193 | 1.54k | sec_lowest_bulk_cost = INT_MAX / 2; |
194 | 1.54k | sec_lowest_bulk_cost_index = width; |
195 | 1.54k | } |
196 | | |
197 | | /* Deal with the first pixel's bulk cost */ |
198 | 13.7M | if (!i) { |
199 | 1.85M | base_bulk_cost++; |
200 | 1.85M | lowest_bulk_cost++; |
201 | 1.85M | sec_lowest_bulk_cost++; |
202 | 1.85M | } |
203 | | |
204 | | /* Look at the bulk cost of the previous loop and see if it is |
205 | | * a new lower bulk cost */ |
206 | 13.7M | prev_bulk_cost = s->length_table[i + 1] + base_bulk_cost; |
207 | 13.7M | if (prev_bulk_cost <= sec_lowest_bulk_cost) { |
208 | | /* If it's lower than the 2nd lowest, then it may be lower |
209 | | * than the lowest */ |
210 | 13.7M | if (prev_bulk_cost <= lowest_bulk_cost) { |
211 | | |
212 | | /* If we have found a new lowest bulk cost, |
213 | | * then the 2nd lowest bulk cost is now farther than the |
214 | | * lowest bulk cost, and will never be used */ |
215 | 12.4M | sec_lowest_bulk_cost = INT_MAX / 2; |
216 | | |
217 | 12.4M | lowest_bulk_cost = prev_bulk_cost; |
218 | 12.4M | lowest_bulk_cost_index = i + 1; |
219 | 12.4M | } else { |
220 | | /* Then it must be the 2nd lowest bulk cost */ |
221 | 1.31M | sec_lowest_bulk_cost = prev_bulk_cost; |
222 | 1.31M | sec_lowest_bulk_cost_index = i + 1; |
223 | 1.31M | } |
224 | 13.7M | } |
225 | | |
226 | 13.7M | if (!s->key_frame && !memcmp(this_line, prev_line, s->pixel_size)) |
227 | 313k | skipcount = FFMIN(skipcount + 1, MAX_RLE_SKIP); |
228 | 13.4M | else |
229 | 13.4M | skipcount = 0; |
230 | | |
231 | 13.7M | total_skip_cost = s->length_table[i + skipcount] + 2; |
232 | 13.7M | s->skip_table[i] = skipcount; |
233 | | |
234 | | |
235 | 13.7M | if (i < width - 1 && !memcmp(this_line, this_line + s->pixel_size, s->pixel_size)) |
236 | 11.3M | repeatcount = FFMIN(repeatcount + 1, MAX_RLE_REPEAT); |
237 | 2.34M | else |
238 | 2.34M | repeatcount = 1; |
239 | | |
240 | 13.7M | total_repeat_cost = s->length_table[i + repeatcount] + 1 + s->pixel_size; |
241 | | |
242 | | /* skip code is free for the first pixel, it costs one byte for repeat and bulk copy |
243 | | * so let's make it aware */ |
244 | 13.7M | if (i == 0) { |
245 | 1.85M | total_skip_cost--; |
246 | 1.85M | total_repeat_cost++; |
247 | 1.85M | } |
248 | | |
249 | 13.7M | if (repeatcount > 1 && (skipcount == 0 || total_repeat_cost < total_skip_cost)) { |
250 | | /* repeat is the best */ |
251 | 11.1M | s->length_table[i] = total_repeat_cost; |
252 | 11.1M | s->rlecode_table[i] = -repeatcount; |
253 | 11.1M | } |
254 | 2.54M | else if (skipcount > 0) { |
255 | | /* skip is the best choice here */ |
256 | 249k | s->length_table[i] = total_skip_cost; |
257 | 249k | s->rlecode_table[i] = 0; |
258 | 249k | } |
259 | 2.29M | else { |
260 | | /* We cannot do neither skip nor repeat |
261 | | * thus we use the best bulk copy */ |
262 | | |
263 | 2.29M | s->length_table[i] = lowest_bulk_cost; |
264 | 2.29M | s->rlecode_table[i] = lowest_bulk_cost_index - i; |
265 | | |
266 | 2.29M | } |
267 | | |
268 | | /* These bulk costs increase every iteration */ |
269 | 13.7M | lowest_bulk_cost += s->pixel_size; |
270 | 13.7M | sec_lowest_bulk_cost += s->pixel_size; |
271 | 13.7M | } |
272 | | |
273 | | /* Good! Now we have the best sequence for this line, let's output it. */ |
274 | | |
275 | | /* We do a special case for the first pixel so that we avoid testing it in |
276 | | * the whole loop */ |
277 | | |
278 | 1.85M | i=0; |
279 | 1.85M | this_line = p-> data[0] + line*p->linesize[0]; |
280 | | |
281 | 1.85M | if (s->rlecode_table[0] == 0) { |
282 | 45.7k | bytestream_put_byte(buf, s->skip_table[0] + 1); |
283 | 45.7k | i += s->skip_table[0]; |
284 | 45.7k | } |
285 | 1.80M | else bytestream_put_byte(buf, 1); |
286 | | |
287 | | |
288 | 3.80M | while (i < width) { |
289 | 1.95M | rlecode = s->rlecode_table[i]; |
290 | 1.95M | bytestream_put_byte(buf, rlecode); |
291 | 1.95M | if (rlecode == 0) { |
292 | | /* Write a skip sequence */ |
293 | 3.85k | bytestream_put_byte(buf, s->skip_table[i] + 1); |
294 | 3.85k | i += s->skip_table[i]; |
295 | 3.85k | } |
296 | 1.95M | else if (rlecode > 0) { |
297 | | /* bulk copy */ |
298 | 1.08M | if (s->avctx->pix_fmt == AV_PIX_FMT_GRAY8) { |
299 | 22.1k | int j; |
300 | | // QT grayscale colorspace has 0=white and 255=black, we will |
301 | | // ignore the palette that is included in the AVFrame because |
302 | | // AV_PIX_FMT_GRAY8 has defined color mapping |
303 | 570k | for (j = 0; j < rlecode*s->pixel_size; ++j) |
304 | 548k | bytestream_put_byte(buf, *(this_line + i*s->pixel_size + j) ^ 0xff); |
305 | 1.06M | } else { |
306 | 1.06M | bytestream_put_buffer(buf, this_line + i*s->pixel_size, rlecode*s->pixel_size); |
307 | 1.06M | } |
308 | 1.08M | i += rlecode; |
309 | 1.08M | } |
310 | 868k | else { |
311 | | /* repeat the bits */ |
312 | 868k | if (s->avctx->pix_fmt == AV_PIX_FMT_GRAY8) { |
313 | 37.0k | int j; |
314 | | // QT grayscale colorspace has 0=white and 255=black, ... |
315 | 185k | for (j = 0; j < s->pixel_size; ++j) |
316 | 148k | bytestream_put_byte(buf, *(this_line + i*s->pixel_size + j) ^ 0xff); |
317 | 831k | } else { |
318 | 831k | bytestream_put_buffer(buf, this_line + i*s->pixel_size, s->pixel_size); |
319 | 831k | } |
320 | 868k | i -= rlecode; |
321 | 868k | } |
322 | 1.95M | } |
323 | 1.85M | bytestream_put_byte(buf, -1); // end RLE line |
324 | 1.85M | } |
325 | | |
326 | | /** Encode frame including header */ |
327 | | static int encode_frame(QtrleEncContext *s, const AVFrame *p, uint8_t *buf) |
328 | 8.91k | { |
329 | 8.91k | int i; |
330 | 8.91k | int start_line = 0; |
331 | 8.91k | int end_line = s->avctx->height; |
332 | 8.91k | uint8_t *orig_buf = buf; |
333 | | |
334 | 8.91k | if (!s->key_frame) { |
335 | 6.88k | unsigned line_size = s->logical_width * s->pixel_size; |
336 | 22.3k | for (start_line = 0; start_line < s->avctx->height; start_line++) |
337 | 21.1k | if (memcmp(p->data[0] + start_line*p->linesize[0], |
338 | 21.1k | s->previous_frame->data[0] + start_line * s->previous_frame->linesize[0], |
339 | 21.1k | line_size)) |
340 | 5.70k | break; |
341 | | |
342 | 19.5k | for (end_line=s->avctx->height; end_line > start_line; end_line--) |
343 | 18.3k | if (memcmp(p->data[0] + (end_line - 1)*p->linesize[0], |
344 | 18.3k | s->previous_frame->data[0] + (end_line - 1) * s->previous_frame->linesize[0], |
345 | 18.3k | line_size)) |
346 | 5.70k | break; |
347 | 6.88k | } |
348 | | |
349 | 8.91k | bytestream_put_be32(&buf, 0); // CHUNK SIZE, patched later |
350 | | |
351 | 8.91k | if ((start_line == 0 && end_line == s->avctx->height) || start_line == s->avctx->height) |
352 | 5.72k | bytestream_put_be16(&buf, 0); // header |
353 | 3.19k | else { |
354 | 3.19k | bytestream_put_be16(&buf, 8); // header |
355 | 3.19k | bytestream_put_be16(&buf, start_line); // starting line |
356 | 3.19k | bytestream_put_be16(&buf, 0); // unknown |
357 | 3.19k | bytestream_put_be16(&buf, end_line - start_line); // lines to update |
358 | 3.19k | bytestream_put_be16(&buf, 0); // unknown |
359 | 3.19k | } |
360 | 1.86M | for (i = start_line; i < end_line; i++) |
361 | 1.85M | qtrle_encode_line(s, p, i, &buf); |
362 | | |
363 | 8.91k | bytestream_put_byte(&buf, 0); // zero skip code = frame finished |
364 | 8.91k | AV_WB32(orig_buf, buf - orig_buf); // patch the chunk size |
365 | 8.91k | return buf - orig_buf; |
366 | 8.91k | } |
367 | | |
368 | | static int qtrle_encode_frame(AVCodecContext *avctx, AVPacket *pkt, |
369 | | const AVFrame *pict, int *got_packet) |
370 | 8.91k | { |
371 | 8.91k | QtrleEncContext * const s = avctx->priv_data; |
372 | 8.91k | int ret; |
373 | | |
374 | 8.91k | if ((ret = ff_alloc_packet(avctx, pkt, s->max_buf_size)) < 0) |
375 | 0 | return ret; |
376 | | |
377 | 8.91k | if (avctx->gop_size == 0 || !s->previous_frame->data[0] || |
378 | 8.91k | (s->avctx->frame_num % avctx->gop_size) == 0) { |
379 | | /* I-Frame */ |
380 | 2.02k | s->key_frame = 1; |
381 | 6.88k | } else { |
382 | | /* P-Frame */ |
383 | 6.88k | s->key_frame = 0; |
384 | 6.88k | } |
385 | | |
386 | 8.91k | pkt->size = encode_frame(s, pict, pkt->data); |
387 | | |
388 | | /* save the current frame */ |
389 | 8.91k | ret = av_frame_replace(s->previous_frame, pict); |
390 | 8.91k | if (ret < 0) { |
391 | 0 | av_log(avctx, AV_LOG_ERROR, "cannot add reference\n"); |
392 | 0 | return ret; |
393 | 0 | } |
394 | | |
395 | 8.91k | if (s->key_frame) |
396 | 2.02k | pkt->flags |= AV_PKT_FLAG_KEY; |
397 | 8.91k | *got_packet = 1; |
398 | | |
399 | 8.91k | return 0; |
400 | 8.91k | } |
401 | | |
402 | | const FFCodec ff_qtrle_encoder = { |
403 | | .p.name = "qtrle", |
404 | | CODEC_LONG_NAME("QuickTime Animation (RLE) video"), |
405 | | .p.type = AVMEDIA_TYPE_VIDEO, |
406 | | .p.id = AV_CODEC_ID_QTRLE, |
407 | | .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, |
408 | | .priv_data_size = sizeof(QtrleEncContext), |
409 | | .init = qtrle_encode_init, |
410 | | FF_CODEC_ENCODE_CB(qtrle_encode_frame), |
411 | | .close = qtrle_encode_end, |
412 | | .p.pix_fmts = (const enum AVPixelFormat[]){ |
413 | | AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB555BE, AV_PIX_FMT_ARGB, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE |
414 | | }, |
415 | | .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, |
416 | | }; |