1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Microsoft RLE decoder
3cabdff1aSopenharmony_ci * Copyright (C) 2008 Konstantin Shishkov
4cabdff1aSopenharmony_ci *
5cabdff1aSopenharmony_ci * This file is part of FFmpeg.
6cabdff1aSopenharmony_ci *
7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
11cabdff1aSopenharmony_ci *
12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15cabdff1aSopenharmony_ci * Lesser General Public License for more details.
16cabdff1aSopenharmony_ci *
17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20cabdff1aSopenharmony_ci */
21cabdff1aSopenharmony_ci
22cabdff1aSopenharmony_ci/**
23cabdff1aSopenharmony_ci * @file
24cabdff1aSopenharmony_ci * MS RLE decoder based on decoder by Mike Melanson and my own for TSCC
25cabdff1aSopenharmony_ci * For more information about the MS RLE format, visit:
26cabdff1aSopenharmony_ci *   http://www.multimedia.cx/msrle.txt
27cabdff1aSopenharmony_ci */
28cabdff1aSopenharmony_ci
29cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h"
30cabdff1aSopenharmony_ci#include "avcodec.h"
31cabdff1aSopenharmony_ci#include "msrledec.h"
32cabdff1aSopenharmony_ci
33cabdff1aSopenharmony_cistatic int msrle_decode_pal4(AVCodecContext *avctx, AVFrame *pic,
34cabdff1aSopenharmony_ci                             GetByteContext *gb)
35cabdff1aSopenharmony_ci{
36cabdff1aSopenharmony_ci    unsigned char rle_code;
37cabdff1aSopenharmony_ci    unsigned char extra_byte, odd_pixel;
38cabdff1aSopenharmony_ci    unsigned char stream_byte;
39cabdff1aSopenharmony_ci    int pixel_ptr = 0;
40cabdff1aSopenharmony_ci    int line = avctx->height - 1;
41cabdff1aSopenharmony_ci    int i;
42cabdff1aSopenharmony_ci
43cabdff1aSopenharmony_ci    while (line >= 0 && pixel_ptr <= avctx->width) {
44cabdff1aSopenharmony_ci        if (bytestream2_get_bytes_left(gb) <= 0) {
45cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR,
46cabdff1aSopenharmony_ci                   "MS RLE: bytestream overrun, %dx%d left\n",
47cabdff1aSopenharmony_ci                   avctx->width - pixel_ptr, line);
48cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
49cabdff1aSopenharmony_ci        }
50cabdff1aSopenharmony_ci        rle_code = stream_byte = bytestream2_get_byteu(gb);
51cabdff1aSopenharmony_ci        if (rle_code == 0) {
52cabdff1aSopenharmony_ci            /* fetch the next byte to see how to handle escape code */
53cabdff1aSopenharmony_ci            stream_byte = bytestream2_get_byte(gb);
54cabdff1aSopenharmony_ci            if (stream_byte == 0) {
55cabdff1aSopenharmony_ci                /* line is done, goto the next one */
56cabdff1aSopenharmony_ci                line--;
57cabdff1aSopenharmony_ci                pixel_ptr = 0;
58cabdff1aSopenharmony_ci            } else if (stream_byte == 1) {
59cabdff1aSopenharmony_ci                /* decode is done */
60cabdff1aSopenharmony_ci                return 0;
61cabdff1aSopenharmony_ci            } else if (stream_byte == 2) {
62cabdff1aSopenharmony_ci                /* reposition frame decode coordinates */
63cabdff1aSopenharmony_ci                stream_byte = bytestream2_get_byte(gb);
64cabdff1aSopenharmony_ci                pixel_ptr += stream_byte;
65cabdff1aSopenharmony_ci                stream_byte = bytestream2_get_byte(gb);
66cabdff1aSopenharmony_ci                line -= stream_byte;
67cabdff1aSopenharmony_ci            } else {
68cabdff1aSopenharmony_ci                // copy pixels from encoded stream
69cabdff1aSopenharmony_ci                odd_pixel =  stream_byte & 1;
70cabdff1aSopenharmony_ci                rle_code = (stream_byte + 1) / 2;
71cabdff1aSopenharmony_ci                extra_byte = rle_code & 0x01;
72cabdff1aSopenharmony_ci                if (pixel_ptr + 2*rle_code - odd_pixel > avctx->width ||
73cabdff1aSopenharmony_ci                    bytestream2_get_bytes_left(gb) < rle_code) {
74cabdff1aSopenharmony_ci                    av_log(avctx, AV_LOG_ERROR,
75cabdff1aSopenharmony_ci                           "MS RLE: frame/stream ptr just went out of bounds (copy)\n");
76cabdff1aSopenharmony_ci                    return AVERROR_INVALIDDATA;
77cabdff1aSopenharmony_ci                }
78cabdff1aSopenharmony_ci
79cabdff1aSopenharmony_ci                for (i = 0; i < rle_code; i++) {
80cabdff1aSopenharmony_ci                    if (pixel_ptr >= avctx->width)
81cabdff1aSopenharmony_ci                        break;
82cabdff1aSopenharmony_ci                    stream_byte = bytestream2_get_byteu(gb);
83cabdff1aSopenharmony_ci                    pic->data[0][line * pic->linesize[0] + pixel_ptr] = stream_byte >> 4;
84cabdff1aSopenharmony_ci                    pixel_ptr++;
85cabdff1aSopenharmony_ci                    if (i + 1 == rle_code && odd_pixel)
86cabdff1aSopenharmony_ci                        break;
87cabdff1aSopenharmony_ci                    if (pixel_ptr >= avctx->width)
88cabdff1aSopenharmony_ci                        break;
89cabdff1aSopenharmony_ci                    pic->data[0][line * pic->linesize[0] + pixel_ptr] = stream_byte & 0x0F;
90cabdff1aSopenharmony_ci                    pixel_ptr++;
91cabdff1aSopenharmony_ci                }
92cabdff1aSopenharmony_ci
93cabdff1aSopenharmony_ci                // if the RLE code is odd, skip a byte in the stream
94cabdff1aSopenharmony_ci                if (extra_byte)
95cabdff1aSopenharmony_ci                    bytestream2_skip(gb, 1);
96cabdff1aSopenharmony_ci            }
97cabdff1aSopenharmony_ci        } else {
98cabdff1aSopenharmony_ci            // decode a run of data
99cabdff1aSopenharmony_ci            if (pixel_ptr + rle_code > avctx->width + 1) {
100cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_ERROR,
101cabdff1aSopenharmony_ci                       "MS RLE: frame ptr just went out of bounds (run) %d %d %d\n", pixel_ptr, rle_code, avctx->width);
102cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
103cabdff1aSopenharmony_ci            }
104cabdff1aSopenharmony_ci            stream_byte = bytestream2_get_byte(gb);
105cabdff1aSopenharmony_ci            for (i = 0; i < rle_code; i++) {
106cabdff1aSopenharmony_ci                if (pixel_ptr >= avctx->width)
107cabdff1aSopenharmony_ci                    break;
108cabdff1aSopenharmony_ci                if ((i & 1) == 0)
109cabdff1aSopenharmony_ci                    pic->data[0][line * pic->linesize[0] + pixel_ptr] = stream_byte >> 4;
110cabdff1aSopenharmony_ci                else
111cabdff1aSopenharmony_ci                    pic->data[0][line * pic->linesize[0] + pixel_ptr] = stream_byte & 0x0F;
112cabdff1aSopenharmony_ci                pixel_ptr++;
113cabdff1aSopenharmony_ci            }
114cabdff1aSopenharmony_ci        }
115cabdff1aSopenharmony_ci    }
116cabdff1aSopenharmony_ci
117cabdff1aSopenharmony_ci    /* one last sanity check on the way out */
118cabdff1aSopenharmony_ci    if (bytestream2_get_bytes_left(gb)) {
119cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
120cabdff1aSopenharmony_ci               "MS RLE: ended frame decode with %d bytes left over\n",
121cabdff1aSopenharmony_ci               bytestream2_get_bytes_left(gb));
122cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
123cabdff1aSopenharmony_ci    }
124cabdff1aSopenharmony_ci
125cabdff1aSopenharmony_ci    return 0;
126cabdff1aSopenharmony_ci}
127cabdff1aSopenharmony_ci
128cabdff1aSopenharmony_ci
129cabdff1aSopenharmony_cistatic int msrle_decode_8_16_24_32(AVCodecContext *avctx, AVFrame *pic,
130cabdff1aSopenharmony_ci                                   int depth, GetByteContext *gb)
131cabdff1aSopenharmony_ci{
132cabdff1aSopenharmony_ci    uint8_t *output, *output_end;
133cabdff1aSopenharmony_ci    int p1, p2, line=avctx->height - 1, pos=0, i;
134cabdff1aSopenharmony_ci    uint16_t pix16;
135cabdff1aSopenharmony_ci    uint32_t pix32;
136cabdff1aSopenharmony_ci    unsigned int width= FFABS(pic->linesize[0]) / (depth >> 3);
137cabdff1aSopenharmony_ci
138cabdff1aSopenharmony_ci    output     = pic->data[0] + (avctx->height - 1) * pic->linesize[0];
139cabdff1aSopenharmony_ci    output_end = output + FFABS(pic->linesize[0]);
140cabdff1aSopenharmony_ci
141cabdff1aSopenharmony_ci    while (bytestream2_get_bytes_left(gb) > 0) {
142cabdff1aSopenharmony_ci        p1 = bytestream2_get_byteu(gb);
143cabdff1aSopenharmony_ci        if(p1 == 0) { //Escape code
144cabdff1aSopenharmony_ci            p2 = bytestream2_get_byte(gb);
145cabdff1aSopenharmony_ci            if(p2 == 0) { //End-of-line
146cabdff1aSopenharmony_ci                if (--line < 0) {
147cabdff1aSopenharmony_ci                    if (bytestream2_get_be16(gb) == 1) { // end-of-picture
148cabdff1aSopenharmony_ci                        return 0;
149cabdff1aSopenharmony_ci                    } else {
150cabdff1aSopenharmony_ci                        av_log(avctx, AV_LOG_ERROR,
151cabdff1aSopenharmony_ci                               "Next line is beyond picture bounds (%d bytes left)\n",
152cabdff1aSopenharmony_ci                               bytestream2_get_bytes_left(gb));
153cabdff1aSopenharmony_ci                        return AVERROR_INVALIDDATA;
154cabdff1aSopenharmony_ci                    }
155cabdff1aSopenharmony_ci                }
156cabdff1aSopenharmony_ci                output = pic->data[0] + line * pic->linesize[0];
157cabdff1aSopenharmony_ci                output_end = output + FFABS(pic->linesize[0]);
158cabdff1aSopenharmony_ci                pos = 0;
159cabdff1aSopenharmony_ci                continue;
160cabdff1aSopenharmony_ci            } else if(p2 == 1) { //End-of-picture
161cabdff1aSopenharmony_ci                return 0;
162cabdff1aSopenharmony_ci            } else if(p2 == 2) { //Skip
163cabdff1aSopenharmony_ci                p1 = bytestream2_get_byte(gb);
164cabdff1aSopenharmony_ci                p2 = bytestream2_get_byte(gb);
165cabdff1aSopenharmony_ci                line -= p2;
166cabdff1aSopenharmony_ci                pos += p1;
167cabdff1aSopenharmony_ci                if (line < 0 || pos >= width){
168cabdff1aSopenharmony_ci                    av_log(avctx, AV_LOG_ERROR, "Skip beyond picture bounds\n");
169cabdff1aSopenharmony_ci                    return -1;
170cabdff1aSopenharmony_ci                }
171cabdff1aSopenharmony_ci                output = pic->data[0] + line * pic->linesize[0] + pos * (depth >> 3);
172cabdff1aSopenharmony_ci                output_end = pic->data[0] + line * pic->linesize[0] + FFABS(pic->linesize[0]);
173cabdff1aSopenharmony_ci                continue;
174cabdff1aSopenharmony_ci            }
175cabdff1aSopenharmony_ci            // Copy data
176cabdff1aSopenharmony_ci            if (output + p2 * (depth >> 3) > output_end) {
177cabdff1aSopenharmony_ci                bytestream2_skip(gb, 2 * (depth >> 3));
178cabdff1aSopenharmony_ci                continue;
179cabdff1aSopenharmony_ci            } else if (bytestream2_get_bytes_left(gb) < p2 * (depth >> 3)) {
180cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_ERROR, "bytestream overrun\n");
181cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
182cabdff1aSopenharmony_ci            }
183cabdff1aSopenharmony_ci
184cabdff1aSopenharmony_ci            if ((depth == 8) || (depth == 24)) {
185cabdff1aSopenharmony_ci                bytestream2_get_bufferu(gb, output, p2 * (depth >> 3));
186cabdff1aSopenharmony_ci                output += p2 * (depth >> 3);
187cabdff1aSopenharmony_ci
188cabdff1aSopenharmony_ci                // RLE8 copy is actually padded - and runs are not!
189cabdff1aSopenharmony_ci                if(depth == 8 && (p2 & 1)) {
190cabdff1aSopenharmony_ci                    bytestream2_skip(gb, 1);
191cabdff1aSopenharmony_ci                }
192cabdff1aSopenharmony_ci            } else if (depth == 16) {
193cabdff1aSopenharmony_ci                for(i = 0; i < p2; i++) {
194cabdff1aSopenharmony_ci                    *(uint16_t*)output = bytestream2_get_le16u(gb);
195cabdff1aSopenharmony_ci                    output += 2;
196cabdff1aSopenharmony_ci                }
197cabdff1aSopenharmony_ci            } else if (depth == 32) {
198cabdff1aSopenharmony_ci                for(i = 0; i < p2; i++) {
199cabdff1aSopenharmony_ci                    *(uint32_t*)output = bytestream2_get_le32u(gb);
200cabdff1aSopenharmony_ci                    output += 4;
201cabdff1aSopenharmony_ci                }
202cabdff1aSopenharmony_ci            }
203cabdff1aSopenharmony_ci            pos += p2;
204cabdff1aSopenharmony_ci        } else { //run of pixels
205cabdff1aSopenharmony_ci            uint8_t pix[3]; //original pixel
206cabdff1aSopenharmony_ci            if (output + p1 * (depth >> 3) > output_end)
207cabdff1aSopenharmony_ci                continue;
208cabdff1aSopenharmony_ci
209cabdff1aSopenharmony_ci            switch(depth){
210cabdff1aSopenharmony_ci            case  8:
211cabdff1aSopenharmony_ci                pix[0] = bytestream2_get_byte(gb);
212cabdff1aSopenharmony_ci                memset(output, pix[0], p1);
213cabdff1aSopenharmony_ci                output += p1;
214cabdff1aSopenharmony_ci                break;
215cabdff1aSopenharmony_ci            case 16:
216cabdff1aSopenharmony_ci                pix16  = bytestream2_get_le16(gb);
217cabdff1aSopenharmony_ci                for(i = 0; i < p1; i++) {
218cabdff1aSopenharmony_ci                        *(uint16_t*)output = pix16;
219cabdff1aSopenharmony_ci                        output += 2;
220cabdff1aSopenharmony_ci                }
221cabdff1aSopenharmony_ci                break;
222cabdff1aSopenharmony_ci            case 24:
223cabdff1aSopenharmony_ci                pix[0] = bytestream2_get_byte(gb);
224cabdff1aSopenharmony_ci                pix[1] = bytestream2_get_byte(gb);
225cabdff1aSopenharmony_ci                pix[2] = bytestream2_get_byte(gb);
226cabdff1aSopenharmony_ci                for(i = 0; i < p1; i++) {
227cabdff1aSopenharmony_ci                        *output++ = pix[0];
228cabdff1aSopenharmony_ci                        *output++ = pix[1];
229cabdff1aSopenharmony_ci                        *output++ = pix[2];
230cabdff1aSopenharmony_ci                }
231cabdff1aSopenharmony_ci                break;
232cabdff1aSopenharmony_ci            case 32:
233cabdff1aSopenharmony_ci                pix32  = bytestream2_get_le32(gb);
234cabdff1aSopenharmony_ci                for(i = 0; i < p1; i++) {
235cabdff1aSopenharmony_ci                        *(uint32_t*)output = pix32;
236cabdff1aSopenharmony_ci                        output += 4;
237cabdff1aSopenharmony_ci                }
238cabdff1aSopenharmony_ci                break;
239cabdff1aSopenharmony_ci            }
240cabdff1aSopenharmony_ci            pos += p1;
241cabdff1aSopenharmony_ci        }
242cabdff1aSopenharmony_ci    }
243cabdff1aSopenharmony_ci
244cabdff1aSopenharmony_ci    av_log(avctx, AV_LOG_WARNING, "MS RLE warning: no end-of-picture code\n");
245cabdff1aSopenharmony_ci    return 0;
246cabdff1aSopenharmony_ci}
247cabdff1aSopenharmony_ci
248cabdff1aSopenharmony_ci
249cabdff1aSopenharmony_ciint ff_msrle_decode(AVCodecContext *avctx, AVFrame *pic,
250cabdff1aSopenharmony_ci                    int depth, GetByteContext *gb)
251cabdff1aSopenharmony_ci{
252cabdff1aSopenharmony_ci    switch(depth){
253cabdff1aSopenharmony_ci    case  4:
254cabdff1aSopenharmony_ci        return msrle_decode_pal4(avctx, pic, gb);
255cabdff1aSopenharmony_ci    case  8:
256cabdff1aSopenharmony_ci    case 16:
257cabdff1aSopenharmony_ci    case 24:
258cabdff1aSopenharmony_ci    case 32:
259cabdff1aSopenharmony_ci        return msrle_decode_8_16_24_32(avctx, pic, depth, gb);
260cabdff1aSopenharmony_ci    default:
261cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Unknown depth %d\n", depth);
262cabdff1aSopenharmony_ci        return -1;
263cabdff1aSopenharmony_ci    }
264cabdff1aSopenharmony_ci}
265