blob: aa4f0e7e15d99c4ae8fa91ed32385c2da1ddbfaa
1 | /* |
2 | * Silicon Graphics RLE 8-bit video decoder |
3 | * Copyright (c) 2012 Peter Ross |
4 | * |
5 | * This file is part of FFmpeg. |
6 | * |
7 | * FFmpeg is free software; you can redistribute it and/or |
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 | * |
12 | * FFmpeg is distributed in the hope that it will be useful, |
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 |
18 | * License along with FFmpeg; if not, write to the Free Software |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | */ |
21 | |
22 | /** |
23 | * @file |
24 | * Silicon Graphics RLE 8-bit video decoder |
25 | * @note Data is packed in rbg323 with rle, contained in mv or mov. |
26 | * The algorithm and pixfmt are subtly different from SGI images. |
27 | */ |
28 | |
29 | #include "libavutil/common.h" |
30 | |
31 | #include "avcodec.h" |
32 | #include "internal.h" |
33 | |
34 | static av_cold int sgirle_decode_init(AVCodecContext *avctx) |
35 | { |
36 | avctx->pix_fmt = AV_PIX_FMT_BGR8; |
37 | return 0; |
38 | } |
39 | |
40 | /** |
41 | * Convert SGI RBG323 pixel into AV_PIX_FMT_BGR8 |
42 | * SGI RGB data is packed as 8bpp, (msb)3R 2B 3G(lsb) |
43 | */ |
44 | #define RBG323_TO_BGR8(x) ((((x) << 3) & 0xC0) | \ |
45 | (((x) << 3) & 0x38) | \ |
46 | (((x) >> 5) & 7)) |
47 | static av_always_inline |
48 | void rbg323_to_bgr8(uint8_t *dst, const uint8_t *src, int size) |
49 | { |
50 | int i; |
51 | for (i = 0; i < size; i++) |
52 | dst[i] = RBG323_TO_BGR8(src[i]); |
53 | } |
54 | |
55 | /** |
56 | * @param[out] dst Destination buffer |
57 | * @param[in] src Source buffer |
58 | * @param src_size Source buffer size (bytes) |
59 | * @param width Width of destination buffer (pixels) |
60 | * @param height Height of destination buffer (pixels) |
61 | * @param linesize Line size of destination buffer (bytes) |
62 | * |
63 | * @return <0 on error |
64 | */ |
65 | static int decode_sgirle8(AVCodecContext *avctx, uint8_t *dst, |
66 | const uint8_t *src, int src_size, |
67 | int width, int height, ptrdiff_t linesize) |
68 | { |
69 | const uint8_t *src_end = src + src_size; |
70 | int x = 0, y = 0; |
71 | |
72 | #define INC_XY(n) \ |
73 | x += n; \ |
74 | if (x >= width) { \ |
75 | y++; \ |
76 | if (y >= height) \ |
77 | return 0; \ |
78 | x = 0; \ |
79 | } |
80 | |
81 | while (src_end - src >= 2) { |
82 | uint8_t v = *src++; |
83 | if (v > 0 && v < 0xC0) { |
84 | do { |
85 | int length = FFMIN(v, width - x); |
86 | if (length <= 0) |
87 | break; |
88 | memset(dst + y * linesize + x, RBG323_TO_BGR8(*src), length); |
89 | INC_XY(length); |
90 | v -= length; |
91 | } while (v > 0); |
92 | src++; |
93 | } else if (v >= 0xC1) { |
94 | v -= 0xC0; |
95 | do { |
96 | int length = FFMIN3(v, width - x, src_end - src); |
97 | if (src_end - src < length || length <= 0) |
98 | break; |
99 | rbg323_to_bgr8(dst + y * linesize + x, src, length); |
100 | INC_XY(length); |
101 | src += length; |
102 | v -= length; |
103 | } while (v > 0); |
104 | } else { |
105 | avpriv_request_sample(avctx, "opcode %d", v); |
106 | return AVERROR_PATCHWELCOME; |
107 | } |
108 | } |
109 | return 0; |
110 | } |
111 | |
112 | static int sgirle_decode_frame(AVCodecContext *avctx, void *data, |
113 | int *got_frame, AVPacket *avpkt) |
114 | { |
115 | AVFrame *frame = data; |
116 | int ret; |
117 | |
118 | if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) |
119 | return ret; |
120 | |
121 | ret = decode_sgirle8(avctx, frame->data[0], avpkt->data, avpkt->size, |
122 | avctx->width, avctx->height, frame->linesize[0]); |
123 | if (ret < 0) |
124 | return ret; |
125 | |
126 | frame->pict_type = AV_PICTURE_TYPE_I; |
127 | frame->key_frame = 1; |
128 | |
129 | *got_frame = 1; |
130 | |
131 | return avpkt->size; |
132 | } |
133 | |
134 | AVCodec ff_sgirle_decoder = { |
135 | .name = "sgirle", |
136 | .long_name = NULL_IF_CONFIG_SMALL("Silicon Graphics RLE 8-bit video"), |
137 | .type = AVMEDIA_TYPE_VIDEO, |
138 | .id = AV_CODEC_ID_SGIRLE, |
139 | .init = sgirle_decode_init, |
140 | .decode = sgirle_decode_frame, |
141 | .capabilities = AV_CODEC_CAP_DR1, |
142 | }; |
143 |