Commit | Line | Data |
---|---|---|
d267b339 CEH |
1 | /* |
2 | * Lagarith lossless decoder | |
3 | * Copyright (c) 2009 Nathan Caldwell <saintdev (at) gmail.com> | |
4 | * | |
2912e87a | 5 | * This file is part of Libav. |
d267b339 | 6 | * |
2912e87a | 7 | * Libav is free software; you can redistribute it and/or |
d267b339 CEH |
8 | * modify it under the terms of the GNU Lesser General Public |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2.1 of the License, or (at your option) any later version. | |
11 | * | |
2912e87a | 12 | * Libav is distributed in the hope that it will be useful, |
d267b339 CEH |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
2912e87a | 18 | * License along with Libav; if not, write to the Free Software |
d267b339 CEH |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | */ | |
21 | ||
22 | /** | |
f25a2ece | 23 | * @file |
d267b339 CEH |
24 | * Lagarith lossless decoder |
25 | * @author Nathan Caldwell | |
26 | */ | |
27 | ||
cc8163e1 DB |
28 | #include <inttypes.h> |
29 | ||
d267b339 CEH |
30 | #include "avcodec.h" |
31 | #include "get_bits.h" | |
32 | #include "mathops.h" | |
33 | #include "dsputil.h" | |
34 | #include "lagarithrac.h" | |
f9150c8a | 35 | #include "thread.h" |
d267b339 CEH |
36 | |
37 | enum LagarithFrameType { | |
adbfc605 DB |
38 | FRAME_RAW = 1, /**< uncompressed */ |
39 | FRAME_U_RGB24 = 2, /**< unaligned RGB24 */ | |
40 | FRAME_ARITH_YUY2 = 3, /**< arithmetic coded YUY2 */ | |
41 | FRAME_ARITH_RGB24 = 4, /**< arithmetic coded RGB24 */ | |
42 | FRAME_SOLID_GRAY = 5, /**< solid grayscale color frame */ | |
43 | FRAME_SOLID_COLOR = 6, /**< solid non-grayscale color frame */ | |
44 | FRAME_OLD_ARITH_RGB = 7, /**< obsolete arithmetic coded RGB (no longer encoded by upstream since version 1.1.0) */ | |
45 | FRAME_ARITH_RGBA = 8, /**< arithmetic coded RGBA */ | |
46 | FRAME_SOLID_RGBA = 9, /**< solid RGBA color frame */ | |
47 | FRAME_ARITH_YV12 = 10, /**< arithmetic coded YV12 */ | |
48 | FRAME_REDUCED_RES = 11, /**< reduced resolution YV12 frame */ | |
d267b339 CEH |
49 | }; |
50 | ||
51 | typedef struct LagarithContext { | |
52 | AVCodecContext *avctx; | |
d267b339 | 53 | DSPContext dsp; |
adbfc605 DB |
54 | int zeros; /**< number of consecutive zero bytes encountered */ |
55 | int zeros_rem; /**< number of zero bytes remaining to output */ | |
ffc638c2 | 56 | uint8_t *rgb_planes; |
4c3e1956 | 57 | int rgb_planes_allocated; |
ffc638c2 | 58 | int rgb_stride; |
d267b339 CEH |
59 | } LagarithContext; |
60 | ||
61 | /** | |
62 | * Compute the 52bit mantissa of 1/(double)denom. | |
63 | * This crazy format uses floats in an entropy coder and we have to match x86 | |
64 | * rounding exactly, thus ordinary floats aren't portable enough. | |
65 | * @param denom denominator | |
66 | * @return 52bit mantissa | |
67 | * @see softfloat_mul | |
68 | */ | |
69 | static uint64_t softfloat_reciprocal(uint32_t denom) | |
70 | { | |
71 | int shift = av_log2(denom - 1) + 1; | |
72 | uint64_t ret = (1ULL << 52) / denom; | |
73 | uint64_t err = (1ULL << 52) - ret * denom; | |
74 | ret <<= shift; | |
75 | err <<= shift; | |
76 | err += denom / 2; | |
77 | return ret + err / denom; | |
78 | } | |
79 | ||
80 | /** | |
81 | * (uint32_t)(x*f), where f has the given mantissa, and exponent 0 | |
82 | * Used in combination with softfloat_reciprocal computes x/(double)denom. | |
83 | * @param x 32bit integer factor | |
84 | * @param mantissa mantissa of f with exponent 0 | |
85 | * @return 32bit integer value (x*f) | |
86 | * @see softfloat_reciprocal | |
87 | */ | |
88 | static uint32_t softfloat_mul(uint32_t x, uint64_t mantissa) | |
89 | { | |
90 | uint64_t l = x * (mantissa & 0xffffffff); | |
91 | uint64_t h = x * (mantissa >> 32); | |
92 | h += l >> 32; | |
93 | l &= 0xffffffff; | |
94 | l += 1 << av_log2(h >> 21); | |
95 | h += l >> 32; | |
96 | return h >> 20; | |
97 | } | |
98 | ||
99 | static uint8_t lag_calc_zero_run(int8_t x) | |
100 | { | |
101 | return (x << 1) ^ (x >> 7); | |
102 | } | |
103 | ||
104 | static int lag_decode_prob(GetBitContext *gb, uint32_t *value) | |
105 | { | |
106 | static const uint8_t series[] = { 1, 2, 3, 5, 8, 13, 21 }; | |
107 | int i; | |
108 | int bit = 0; | |
109 | int bits = 0; | |
110 | int prevbit = 0; | |
111 | unsigned val; | |
112 | ||
113 | for (i = 0; i < 7; i++) { | |
114 | if (prevbit && bit) | |
115 | break; | |
116 | prevbit = bit; | |
117 | bit = get_bits1(gb); | |
118 | if (bit && !prevbit) | |
119 | bits += series[i]; | |
120 | } | |
121 | bits--; | |
122 | if (bits < 0 || bits > 31) { | |
123 | *value = 0; | |
124 | return -1; | |
125 | } else if (bits == 0) { | |
126 | *value = 0; | |
127 | return 0; | |
128 | } | |
129 | ||
130 | val = get_bits_long(gb, bits); | |
131 | val |= 1 << bits; | |
132 | ||
133 | *value = val - 1; | |
134 | ||
135 | return 0; | |
136 | } | |
137 | ||
138 | static int lag_read_prob_header(lag_rac *rac, GetBitContext *gb) | |
139 | { | |
140 | int i, j, scale_factor; | |
141 | unsigned prob, cumulative_target; | |
142 | unsigned cumul_prob = 0; | |
143 | unsigned scaled_cumul_prob = 0; | |
144 | ||
145 | rac->prob[0] = 0; | |
146 | rac->prob[257] = UINT_MAX; | |
147 | /* Read probabilities from bitstream */ | |
148 | for (i = 1; i < 257; i++) { | |
149 | if (lag_decode_prob(gb, &rac->prob[i]) < 0) { | |
150 | av_log(rac->avctx, AV_LOG_ERROR, "Invalid probability encountered.\n"); | |
151 | return -1; | |
152 | } | |
153 | if ((uint64_t)cumul_prob + rac->prob[i] > UINT_MAX) { | |
154 | av_log(rac->avctx, AV_LOG_ERROR, "Integer overflow encountered in cumulative probability calculation.\n"); | |
155 | return -1; | |
156 | } | |
157 | cumul_prob += rac->prob[i]; | |
158 | if (!rac->prob[i]) { | |
159 | if (lag_decode_prob(gb, &prob)) { | |
160 | av_log(rac->avctx, AV_LOG_ERROR, "Invalid probability run encountered.\n"); | |
161 | return -1; | |
162 | } | |
163 | if (prob > 257 - i) | |
164 | prob = 257 - i; | |
165 | for (j = 0; j < prob; j++) | |
166 | rac->prob[++i] = 0; | |
167 | } | |
168 | } | |
169 | ||
170 | if (!cumul_prob) { | |
171 | av_log(rac->avctx, AV_LOG_ERROR, "All probabilities are 0!\n"); | |
172 | return -1; | |
173 | } | |
174 | ||
175 | /* Scale probabilities so cumulative probability is an even power of 2. */ | |
176 | scale_factor = av_log2(cumul_prob); | |
177 | ||
178 | if (cumul_prob & (cumul_prob - 1)) { | |
179 | uint64_t mul = softfloat_reciprocal(cumul_prob); | |
180 | for (i = 1; i < 257; i++) { | |
181 | rac->prob[i] = softfloat_mul(rac->prob[i], mul); | |
182 | scaled_cumul_prob += rac->prob[i]; | |
183 | } | |
184 | ||
185 | scale_factor++; | |
186 | cumulative_target = 1 << scale_factor; | |
187 | ||
188 | if (scaled_cumul_prob > cumulative_target) { | |
189 | av_log(rac->avctx, AV_LOG_ERROR, | |
190 | "Scaled probabilities are larger than target!\n"); | |
191 | return -1; | |
192 | } | |
193 | ||
194 | scaled_cumul_prob = cumulative_target - scaled_cumul_prob; | |
195 | ||
196 | for (i = 1; scaled_cumul_prob; i = (i & 0x7f) + 1) { | |
197 | if (rac->prob[i]) { | |
198 | rac->prob[i]++; | |
199 | scaled_cumul_prob--; | |
200 | } | |
201 | /* Comment from reference source: | |
202 | * if (b & 0x80 == 0) { // order of operations is 'wrong'; it has been left this way | |
511cf612 DB |
203 | * // since the compression change is negligible and fixing it |
204 | * // breaks backwards compatibility | |
d267b339 CEH |
205 | * b =- (signed int)b; |
206 | * b &= 0xFF; | |
207 | * } else { | |
208 | * b++; | |
209 | * b &= 0x7f; | |
210 | * } | |
211 | */ | |
212 | } | |
213 | } | |
214 | ||
215 | rac->scale = scale_factor; | |
216 | ||
217 | /* Fill probability array with cumulative probability for each symbol. */ | |
218 | for (i = 1; i < 257; i++) | |
219 | rac->prob[i] += rac->prob[i - 1]; | |
220 | ||
221 | return 0; | |
222 | } | |
223 | ||
224 | static void add_lag_median_prediction(uint8_t *dst, uint8_t *src1, | |
225 | uint8_t *diff, int w, int *left, | |
226 | int *left_top) | |
227 | { | |
228 | /* This is almost identical to add_hfyu_median_prediction in dsputil.h. | |
229 | * However the &0xFF on the gradient predictor yealds incorrect output | |
230 | * for lagarith. | |
231 | */ | |
232 | int i; | |
233 | uint8_t l, lt; | |
234 | ||
235 | l = *left; | |
236 | lt = *left_top; | |
237 | ||
238 | for (i = 0; i < w; i++) { | |
239 | l = mid_pred(l, src1[i], l + src1[i] - lt) + diff[i]; | |
240 | lt = src1[i]; | |
241 | dst[i] = l; | |
242 | } | |
243 | ||
244 | *left = l; | |
245 | *left_top = lt; | |
246 | } | |
247 | ||
248 | static void lag_pred_line(LagarithContext *l, uint8_t *buf, | |
249 | int width, int stride, int line) | |
250 | { | |
251 | int L, TL; | |
252 | ||
253 | if (!line) { | |
2f970946 | 254 | int i, align_width = (width - 1) & ~31; |
d267b339 CEH |
255 | /* Left prediction only for first line */ |
256 | L = l->dsp.add_hfyu_left_prediction(buf + 1, buf + 1, | |
2f970946 KS |
257 | align_width, buf[0]); |
258 | for (i = align_width + 1; i < width; i++) | |
259 | buf[i] += buf[i - 1]; | |
d267b339 | 260 | } else { |
0a82f527 RB |
261 | /* Left pixel is actually prev_row[width] */ |
262 | L = buf[width - stride - 1]; | |
263 | ||
264 | if (line == 1) { | |
265 | /* Second line, left predict first pixel, the rest of the line is median predicted | |
266 | * NOTE: In the case of RGB this pixel is top predicted */ | |
716d413c | 267 | TL = l->avctx->pix_fmt == AV_PIX_FMT_YUV420P ? buf[-stride] : L; |
0a82f527 RB |
268 | } else { |
269 | /* Top left is 2 rows back, last pixel */ | |
270 | TL = buf[width - (2 * stride) - 1]; | |
271 | } | |
d267b339 | 272 | |
0a82f527 RB |
273 | add_lag_median_prediction(buf, buf - stride, buf, |
274 | width, &L, &TL); | |
275 | } | |
d267b339 CEH |
276 | } |
277 | ||
464e9ab0 KS |
278 | static void lag_pred_line_yuy2(LagarithContext *l, uint8_t *buf, |
279 | int width, int stride, int line, | |
280 | int is_luma) | |
281 | { | |
282 | int L, TL; | |
283 | ||
284 | if (!line) { | |
2f970946 | 285 | int i, align_width; |
464e9ab0 KS |
286 | if (is_luma) { |
287 | buf++; | |
288 | width--; | |
289 | } | |
2f970946 KS |
290 | |
291 | align_width = (width - 1) & ~31; | |
292 | l->dsp.add_hfyu_left_prediction(buf + 1, buf + 1, align_width, buf[0]); | |
293 | ||
294 | for (i = align_width + 1; i < width; i++) | |
295 | buf[i] += buf[i - 1]; | |
296 | ||
464e9ab0 KS |
297 | return; |
298 | } | |
299 | if (line == 1) { | |
300 | const int HEAD = is_luma ? 4 : 2; | |
301 | int i; | |
302 | ||
303 | L = buf[width - stride - 1]; | |
304 | TL = buf[HEAD - stride - 1]; | |
305 | for (i = 0; i < HEAD; i++) { | |
306 | L += buf[i]; | |
307 | buf[i] = L; | |
308 | } | |
2f970946 KS |
309 | for (; i < width; i++) { |
310 | L = mid_pred(L & 0xFF, buf[i - stride], (L + buf[i - stride] - TL) & 0xFF) + buf[i]; | |
311 | TL = buf[i - stride]; | |
312 | buf[i] = L; | |
313 | } | |
464e9ab0 KS |
314 | } else { |
315 | TL = buf[width - (2 * stride) - 1]; | |
316 | L = buf[width - stride - 1]; | |
2f970946 KS |
317 | l->dsp.add_hfyu_median_prediction(buf, buf - stride, buf, width, |
318 | &L, &TL); | |
464e9ab0 | 319 | } |
464e9ab0 KS |
320 | } |
321 | ||
d267b339 CEH |
322 | static int lag_decode_line(LagarithContext *l, lag_rac *rac, |
323 | uint8_t *dst, int width, int stride, | |
324 | int esc_count) | |
325 | { | |
326 | int i = 0; | |
327 | int ret = 0; | |
328 | ||
329 | if (!esc_count) | |
330 | esc_count = -1; | |
331 | ||
332 | /* Output any zeros remaining from the previous run */ | |
333 | handle_zeros: | |
334 | if (l->zeros_rem) { | |
335 | int count = FFMIN(l->zeros_rem, width - i); | |
336 | memset(dst + i, 0, count); | |
337 | i += count; | |
338 | l->zeros_rem -= count; | |
339 | } | |
340 | ||
341 | while (i < width) { | |
342 | dst[i] = lag_get_rac(rac); | |
343 | ret++; | |
344 | ||
345 | if (dst[i]) | |
346 | l->zeros = 0; | |
347 | else | |
348 | l->zeros++; | |
349 | ||
350 | i++; | |
351 | if (l->zeros == esc_count) { | |
352 | int index = lag_get_rac(rac); | |
353 | ret++; | |
354 | ||
355 | l->zeros = 0; | |
356 | ||
357 | l->zeros_rem = lag_calc_zero_run(index); | |
358 | goto handle_zeros; | |
359 | } | |
360 | } | |
361 | return ret; | |
362 | } | |
363 | ||
364 | static int lag_decode_zero_run_line(LagarithContext *l, uint8_t *dst, | |
0a82f527 RB |
365 | const uint8_t *src, const uint8_t *src_end, |
366 | int width, int esc_count) | |
d267b339 CEH |
367 | { |
368 | int i = 0; | |
369 | int count; | |
370 | uint8_t zero_run = 0; | |
0a82f527 | 371 | const uint8_t *src_start = src; |
d267b339 CEH |
372 | uint8_t mask1 = -(esc_count < 2); |
373 | uint8_t mask2 = -(esc_count < 3); | |
374 | uint8_t *end = dst + (width - 2); | |
375 | ||
376 | output_zeros: | |
377 | if (l->zeros_rem) { | |
378 | count = FFMIN(l->zeros_rem, width - i); | |
b631e4ed MN |
379 | if (end - dst < count) { |
380 | av_log(l->avctx, AV_LOG_ERROR, "Too many zeros remaining.\n"); | |
381 | return AVERROR_INVALIDDATA; | |
382 | } | |
383 | ||
d267b339 CEH |
384 | memset(dst, 0, count); |
385 | l->zeros_rem -= count; | |
386 | dst += count; | |
387 | } | |
388 | ||
389 | while (dst < end) { | |
390 | i = 0; | |
391 | while (!zero_run && dst + i < end) { | |
392 | i++; | |
0a82f527 RB |
393 | if (src + i >= src_end) |
394 | return AVERROR_INVALIDDATA; | |
d267b339 CEH |
395 | zero_run = |
396 | !(src[i] | (src[i + 1] & mask1) | (src[i + 2] & mask2)); | |
397 | } | |
398 | if (zero_run) { | |
399 | zero_run = 0; | |
400 | i += esc_count; | |
401 | memcpy(dst, src, i); | |
402 | dst += i; | |
403 | l->zeros_rem = lag_calc_zero_run(src[i]); | |
404 | ||
405 | src += i + 1; | |
406 | goto output_zeros; | |
407 | } else { | |
408 | memcpy(dst, src, i); | |
409 | src += i; | |
0a82f527 | 410 | dst += i; |
d267b339 CEH |
411 | } |
412 | } | |
0a82f527 | 413 | return src_start - src; |
d267b339 CEH |
414 | } |
415 | ||
416 | ||
417 | ||
418 | static int lag_decode_arith_plane(LagarithContext *l, uint8_t *dst, | |
419 | int width, int height, int stride, | |
420 | const uint8_t *src, int src_size) | |
421 | { | |
422 | int i = 0; | |
423 | int read = 0; | |
424 | uint32_t length; | |
425 | uint32_t offset = 1; | |
426 | int esc_count = src[0]; | |
427 | GetBitContext gb; | |
428 | lag_rac rac; | |
0a82f527 | 429 | const uint8_t *src_end = src + src_size; |
d267b339 CEH |
430 | |
431 | rac.avctx = l->avctx; | |
432 | l->zeros = 0; | |
433 | ||
434 | if (esc_count < 4) { | |
435 | length = width * height; | |
436 | if (esc_count && AV_RL32(src + 1) < length) { | |
437 | length = AV_RL32(src + 1); | |
438 | offset += 4; | |
439 | } | |
440 | ||
441 | init_get_bits(&gb, src + offset, src_size * 8); | |
442 | ||
443 | if (lag_read_prob_header(&rac, &gb) < 0) | |
444 | return -1; | |
445 | ||
e9ca85e7 | 446 | ff_lag_rac_init(&rac, &gb, length - stride); |
d267b339 CEH |
447 | |
448 | for (i = 0; i < height; i++) | |
449 | read += lag_decode_line(l, &rac, dst + (i * stride), width, | |
450 | stride, esc_count); | |
451 | ||
452 | if (read > length) | |
453 | av_log(l->avctx, AV_LOG_WARNING, | |
cc8163e1 | 454 | "Output more bytes than length (%d of %"PRIu32")\n", read, |
d267b339 CEH |
455 | length); |
456 | } else if (esc_count < 8) { | |
457 | esc_count -= 4; | |
458 | if (esc_count > 0) { | |
459 | /* Zero run coding only, no range coding. */ | |
0a82f527 RB |
460 | for (i = 0; i < height; i++) { |
461 | int res = lag_decode_zero_run_line(l, dst + (i * stride), src, | |
462 | src_end, width, esc_count); | |
463 | if (res < 0) | |
464 | return res; | |
465 | src += res; | |
466 | } | |
d267b339 | 467 | } else { |
0a82f527 RB |
468 | if (src_size < width * height) |
469 | return AVERROR_INVALIDDATA; // buffer not big enough | |
d267b339 CEH |
470 | /* Plane is stored uncompressed */ |
471 | for (i = 0; i < height; i++) { | |
472 | memcpy(dst + (i * stride), src, width); | |
473 | src += width; | |
474 | } | |
475 | } | |
476 | } else if (esc_count == 0xff) { | |
b0c8b8a6 | 477 | /* Plane is a solid run of given value */ |
d267b339 | 478 | for (i = 0; i < height; i++) |
b0c8b8a6 RD |
479 | memset(dst + i * stride, src[1], width); |
480 | /* Do not apply prediction. | |
481 | Note: memset to 0 above, setting first value to src[1] | |
482 | and applying prediction gives the same result. */ | |
483 | return 0; | |
d267b339 CEH |
484 | } else { |
485 | av_log(l->avctx, AV_LOG_ERROR, | |
486 | "Invalid zero run escape code! (%#x)\n", esc_count); | |
487 | return -1; | |
488 | } | |
489 | ||
716d413c | 490 | if (l->avctx->pix_fmt != AV_PIX_FMT_YUV422P) { |
464e9ab0 KS |
491 | for (i = 0; i < height; i++) { |
492 | lag_pred_line(l, dst, width, stride, i); | |
493 | dst += stride; | |
494 | } | |
495 | } else { | |
496 | for (i = 0; i < height; i++) { | |
497 | lag_pred_line_yuy2(l, dst, width, stride, i, | |
498 | width == l->avctx->width); | |
499 | dst += stride; | |
500 | } | |
d267b339 CEH |
501 | } |
502 | ||
503 | return 0; | |
504 | } | |
505 | ||
506 | /** | |
507 | * Decode a frame. | |
508 | * @param avctx codec context | |
509 | * @param data output AVFrame | |
510 | * @param data_size size of output data or 0 if no picture is returned | |
511 | * @param avpkt input packet | |
512 | * @return number of consumed bytes on success or negative if decode fails | |
513 | */ | |
514 | static int lag_decode_frame(AVCodecContext *avctx, | |
df9b9567 | 515 | void *data, int *got_frame, AVPacket *avpkt) |
d267b339 CEH |
516 | { |
517 | const uint8_t *buf = avpkt->data; | |
518 | int buf_size = avpkt->size; | |
519 | LagarithContext *l = avctx->priv_data; | |
759001c5 AK |
520 | ThreadFrame frame = { .f = data }; |
521 | AVFrame *const p = data; | |
d267b339 CEH |
522 | uint8_t frametype = 0; |
523 | uint32_t offset_gu = 0, offset_bv = 0, offset_ry = 9; | |
1fdb5649 | 524 | uint32_t offs[4]; |
ffc638c2 | 525 | uint8_t *srcs[4], *dst; |
7af507ea | 526 | int i, j, planes = 3; |
d267b339 | 527 | |
d267b339 CEH |
528 | p->key_frame = 1; |
529 | ||
530 | frametype = buf[0]; | |
531 | ||
532 | offset_gu = AV_RL32(buf + 1); | |
533 | offset_bv = AV_RL32(buf + 5); | |
534 | ||
535 | switch (frametype) { | |
ffc638c2 | 536 | case FRAME_SOLID_RGBA: |
716d413c | 537 | avctx->pix_fmt = AV_PIX_FMT_RGB32; |
ffc638c2 | 538 | |
759001c5 | 539 | if (ff_thread_get_buffer(avctx, &frame, 0) < 0) { |
ffc638c2 KS |
540 | av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); |
541 | return -1; | |
542 | } | |
543 | ||
544 | dst = p->data[0]; | |
545 | for (j = 0; j < avctx->height; j++) { | |
546 | for (i = 0; i < avctx->width; i++) | |
547 | AV_WN32(dst + i * 4, offset_gu); | |
548 | dst += p->linesize[0]; | |
549 | } | |
550 | break; | |
551 | case FRAME_ARITH_RGBA: | |
716d413c | 552 | avctx->pix_fmt = AV_PIX_FMT_RGB32; |
7af507ea TW |
553 | planes = 4; |
554 | offset_ry += 4; | |
555 | offs[3] = AV_RL32(buf + 9); | |
556 | case FRAME_ARITH_RGB24: | |
58637a0b CEH |
557 | case FRAME_U_RGB24: |
558 | if (frametype == FRAME_ARITH_RGB24 || frametype == FRAME_U_RGB24) | |
716d413c | 559 | avctx->pix_fmt = AV_PIX_FMT_RGB24; |
ffc638c2 | 560 | |
759001c5 | 561 | if (ff_thread_get_buffer(avctx, &frame, 0) < 0) { |
ffc638c2 KS |
562 | av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); |
563 | return -1; | |
564 | } | |
7af507ea | 565 | |
ffc638c2 KS |
566 | offs[0] = offset_bv; |
567 | offs[1] = offset_gu; | |
7af507ea | 568 | offs[2] = offset_ry; |
ffc638c2 | 569 | |
4c3e1956 AK |
570 | l->rgb_stride = FFALIGN(avctx->width, 16); |
571 | av_fast_malloc(&l->rgb_planes, &l->rgb_planes_allocated, | |
572 | l->rgb_stride * avctx->height * planes + 1); | |
ffc638c2 | 573 | if (!l->rgb_planes) { |
4c3e1956 AK |
574 | av_log(avctx, AV_LOG_ERROR, "cannot allocate temporary buffer\n"); |
575 | return AVERROR(ENOMEM); | |
ffc638c2 | 576 | } |
7af507ea | 577 | for (i = 0; i < planes; i++) |
ffc638c2 | 578 | srcs[i] = l->rgb_planes + (i + 1) * l->rgb_stride * avctx->height - l->rgb_stride; |
0a82f527 RB |
579 | if (offset_ry >= buf_size || |
580 | offset_gu >= buf_size || | |
581 | offset_bv >= buf_size || | |
582 | (planes == 4 && offs[3] >= buf_size)) { | |
583 | av_log(avctx, AV_LOG_ERROR, | |
584 | "Invalid frame offsets\n"); | |
585 | return AVERROR_INVALIDDATA; | |
586 | } | |
7af507ea | 587 | for (i = 0; i < planes; i++) |
ffc638c2 KS |
588 | lag_decode_arith_plane(l, srcs[i], |
589 | avctx->width, avctx->height, | |
590 | -l->rgb_stride, buf + offs[i], | |
0a82f527 | 591 | buf_size - offs[i]); |
ffc638c2 | 592 | dst = p->data[0]; |
7af507ea | 593 | for (i = 0; i < planes; i++) |
ffc638c2 KS |
594 | srcs[i] = l->rgb_planes + i * l->rgb_stride * avctx->height; |
595 | for (j = 0; j < avctx->height; j++) { | |
596 | for (i = 0; i < avctx->width; i++) { | |
597 | uint8_t r, g, b, a; | |
598 | r = srcs[0][i]; | |
599 | g = srcs[1][i]; | |
600 | b = srcs[2][i]; | |
ffc638c2 KS |
601 | r += g; |
602 | b += g; | |
7af507ea TW |
603 | if (frametype == FRAME_ARITH_RGBA) { |
604 | a = srcs[3][i]; | |
605 | AV_WN32(dst + i * 4, MKBETAG(a, r, g, b)); | |
606 | } else { | |
607 | dst[i * 3 + 0] = r; | |
608 | dst[i * 3 + 1] = g; | |
609 | dst[i * 3 + 2] = b; | |
610 | } | |
ffc638c2 KS |
611 | } |
612 | dst += p->linesize[0]; | |
7af507ea | 613 | for (i = 0; i < planes; i++) |
ffc638c2 KS |
614 | srcs[i] += l->rgb_stride; |
615 | } | |
616 | break; | |
464e9ab0 | 617 | case FRAME_ARITH_YUY2: |
716d413c | 618 | avctx->pix_fmt = AV_PIX_FMT_YUV422P; |
464e9ab0 | 619 | |
759001c5 | 620 | if (ff_thread_get_buffer(avctx, &frame, 0) < 0) { |
464e9ab0 KS |
621 | av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); |
622 | return -1; | |
623 | } | |
624 | ||
625 | if (offset_ry >= buf_size || | |
626 | offset_gu >= buf_size || | |
627 | offset_bv >= buf_size) { | |
628 | av_log(avctx, AV_LOG_ERROR, | |
629 | "Invalid frame offsets\n"); | |
630 | return AVERROR_INVALIDDATA; | |
631 | } | |
632 | ||
633 | lag_decode_arith_plane(l, p->data[0], avctx->width, avctx->height, | |
634 | p->linesize[0], buf + offset_ry, | |
635 | buf_size - offset_ry); | |
464e9ab0 KS |
636 | lag_decode_arith_plane(l, p->data[1], avctx->width / 2, |
637 | avctx->height, p->linesize[1], | |
7191e1c4 RB |
638 | buf + offset_gu, buf_size - offset_gu); |
639 | lag_decode_arith_plane(l, p->data[2], avctx->width / 2, | |
640 | avctx->height, p->linesize[2], | |
464e9ab0 KS |
641 | buf + offset_bv, buf_size - offset_bv); |
642 | break; | |
d267b339 | 643 | case FRAME_ARITH_YV12: |
716d413c | 644 | avctx->pix_fmt = AV_PIX_FMT_YUV420P; |
d267b339 | 645 | |
759001c5 | 646 | if (ff_thread_get_buffer(avctx, &frame, 0) < 0) { |
d267b339 CEH |
647 | av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); |
648 | return -1; | |
649 | } | |
650 | ||
0a82f527 RB |
651 | if (offset_ry >= buf_size || |
652 | offset_gu >= buf_size || | |
653 | offset_bv >= buf_size) { | |
654 | av_log(avctx, AV_LOG_ERROR, | |
655 | "Invalid frame offsets\n"); | |
656 | return AVERROR_INVALIDDATA; | |
657 | } | |
658 | ||
d267b339 CEH |
659 | lag_decode_arith_plane(l, p->data[0], avctx->width, avctx->height, |
660 | p->linesize[0], buf + offset_ry, | |
0a82f527 | 661 | buf_size - offset_ry); |
d267b339 CEH |
662 | lag_decode_arith_plane(l, p->data[2], avctx->width / 2, |
663 | avctx->height / 2, p->linesize[2], | |
0a82f527 | 664 | buf + offset_gu, buf_size - offset_gu); |
d267b339 CEH |
665 | lag_decode_arith_plane(l, p->data[1], avctx->width / 2, |
666 | avctx->height / 2, p->linesize[1], | |
0a82f527 | 667 | buf + offset_bv, buf_size - offset_bv); |
d267b339 CEH |
668 | break; |
669 | default: | |
670 | av_log(avctx, AV_LOG_ERROR, | |
4f484037 | 671 | "Unsupported Lagarith frame type: %#"PRIx8"\n", frametype); |
d267b339 CEH |
672 | return -1; |
673 | } | |
674 | ||
df9b9567 | 675 | *got_frame = 1; |
d267b339 CEH |
676 | |
677 | return buf_size; | |
678 | } | |
679 | ||
680 | static av_cold int lag_decode_init(AVCodecContext *avctx) | |
681 | { | |
682 | LagarithContext *l = avctx->priv_data; | |
683 | l->avctx = avctx; | |
684 | ||
9cf0841e | 685 | ff_dsputil_init(&l->dsp, avctx); |
d267b339 CEH |
686 | |
687 | return 0; | |
688 | } | |
689 | ||
690 | static av_cold int lag_decode_end(AVCodecContext *avctx) | |
691 | { | |
692 | LagarithContext *l = avctx->priv_data; | |
693 | ||
ffc638c2 | 694 | av_freep(&l->rgb_planes); |
d267b339 CEH |
695 | |
696 | return 0; | |
697 | } | |
698 | ||
d36beb3f | 699 | AVCodec ff_lagarith_decoder = { |
ec6402b7 | 700 | .name = "lagarith", |
b2bed932 | 701 | .long_name = NULL_IF_CONFIG_SMALL("Lagarith lossless"), |
ec6402b7 | 702 | .type = AVMEDIA_TYPE_VIDEO, |
36ef5369 | 703 | .id = AV_CODEC_ID_LAGARITH, |
ec6402b7 AK |
704 | .priv_data_size = sizeof(LagarithContext), |
705 | .init = lag_decode_init, | |
706 | .close = lag_decode_end, | |
707 | .decode = lag_decode_frame, | |
f9150c8a | 708 | .capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS, |
d267b339 | 709 | }; |