Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
2 | * Microsoft RLE video decoder | |
3 | * Copyright (c) 2003 The FFmpeg Project | |
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 | * MS RLE video decoder by Mike Melanson (melanson@pcisys.net) | |
25 | * For more information about the MS RLE format, visit: | |
26 | * http://www.pcisys.net/~melanson/codecs/ | |
27 | * | |
28 | * The MS RLE decoder outputs PAL8 colorspace data. | |
29 | */ | |
30 | ||
31 | #include <stdio.h> | |
32 | #include <stdlib.h> | |
33 | #include <string.h> | |
34 | ||
35 | #include "avcodec.h" | |
36 | #include "internal.h" | |
37 | #include "msrledec.h" | |
38 | #include "libavutil/imgutils.h" | |
39 | ||
40 | typedef struct MsrleContext { | |
41 | AVCodecContext *avctx; | |
42 | AVFrame *frame; | |
43 | ||
44 | GetByteContext gb; | |
45 | const unsigned char *buf; | |
46 | int size; | |
47 | ||
48 | uint32_t pal[256]; | |
49 | } MsrleContext; | |
50 | ||
51 | static av_cold int msrle_decode_init(AVCodecContext *avctx) | |
52 | { | |
53 | MsrleContext *s = avctx->priv_data; | |
54 | int i; | |
55 | ||
56 | s->avctx = avctx; | |
57 | ||
58 | switch (avctx->bits_per_coded_sample) { | |
59 | case 1: | |
60 | avctx->pix_fmt = AV_PIX_FMT_MONOWHITE; | |
61 | break; | |
62 | case 4: | |
63 | case 8: | |
64 | avctx->pix_fmt = AV_PIX_FMT_PAL8; | |
65 | break; | |
66 | case 24: | |
67 | avctx->pix_fmt = AV_PIX_FMT_BGR24; | |
68 | break; | |
69 | default: | |
70 | av_log(avctx, AV_LOG_ERROR, "unsupported bits per sample\n"); | |
71 | return AVERROR_INVALIDDATA; | |
72 | } | |
73 | ||
74 | s->frame = av_frame_alloc(); | |
75 | if (!s->frame) | |
76 | return AVERROR(ENOMEM); | |
77 | ||
78 | if (avctx->extradata_size >= 4) | |
79 | for (i = 0; i < FFMIN(avctx->extradata_size, AVPALETTE_SIZE)/4; i++) | |
80 | s->pal[i] = 0xFFU<<24 | AV_RL32(avctx->extradata+4*i); | |
81 | ||
82 | return 0; | |
83 | } | |
84 | ||
85 | static int msrle_decode_frame(AVCodecContext *avctx, | |
86 | void *data, int *got_frame, | |
87 | AVPacket *avpkt) | |
88 | { | |
89 | const uint8_t *buf = avpkt->data; | |
90 | int buf_size = avpkt->size; | |
91 | MsrleContext *s = avctx->priv_data; | |
92 | int istride = FFALIGN(avctx->width*avctx->bits_per_coded_sample, 32) / 8; | |
93 | int ret; | |
94 | ||
95 | s->buf = buf; | |
96 | s->size = buf_size; | |
97 | ||
98 | if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) | |
99 | return ret; | |
100 | ||
101 | if (avctx->bits_per_coded_sample > 1 && avctx->bits_per_coded_sample <= 8) { | |
102 | const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, NULL); | |
103 | ||
104 | if (pal) { | |
105 | s->frame->palette_has_changed = 1; | |
106 | memcpy(s->pal, pal, AVPALETTE_SIZE); | |
107 | } | |
108 | /* make the palette available */ | |
109 | memcpy(s->frame->data[1], s->pal, AVPALETTE_SIZE); | |
110 | } | |
111 | ||
112 | /* FIXME how to correctly detect RLE ??? */ | |
113 | if (avctx->height * istride == avpkt->size) { /* assume uncompressed */ | |
114 | int linesize = av_image_get_linesize(avctx->pix_fmt, avctx->width, 0); | |
115 | uint8_t *ptr = s->frame->data[0]; | |
116 | uint8_t *buf = avpkt->data + (avctx->height-1)*istride; | |
117 | int i, j; | |
118 | ||
119 | if (linesize < 0) | |
120 | return linesize; | |
121 | ||
122 | for (i = 0; i < avctx->height; i++) { | |
123 | if (avctx->bits_per_coded_sample == 4) { | |
124 | for (j = 0; j < avctx->width - 1; j += 2) { | |
125 | ptr[j+0] = buf[j>>1] >> 4; | |
126 | ptr[j+1] = buf[j>>1] & 0xF; | |
127 | } | |
128 | if (avctx->width & 1) | |
129 | ptr[j+0] = buf[j>>1] >> 4; | |
130 | } else { | |
131 | memcpy(ptr, buf, linesize); | |
132 | } | |
133 | buf -= istride; | |
134 | ptr += s->frame->linesize[0]; | |
135 | } | |
136 | } else { | |
137 | bytestream2_init(&s->gb, buf, buf_size); | |
138 | ff_msrle_decode(avctx, (AVPicture*)s->frame, avctx->bits_per_coded_sample, &s->gb); | |
139 | } | |
140 | ||
141 | if ((ret = av_frame_ref(data, s->frame)) < 0) | |
142 | return ret; | |
143 | ||
144 | *got_frame = 1; | |
145 | ||
146 | /* report that the buffer was completely consumed */ | |
147 | return buf_size; | |
148 | } | |
149 | ||
150 | static av_cold int msrle_decode_end(AVCodecContext *avctx) | |
151 | { | |
152 | MsrleContext *s = avctx->priv_data; | |
153 | ||
154 | /* release the last frame */ | |
155 | av_frame_free(&s->frame); | |
156 | ||
157 | return 0; | |
158 | } | |
159 | ||
160 | AVCodec ff_msrle_decoder = { | |
161 | .name = "msrle", | |
162 | .long_name = NULL_IF_CONFIG_SMALL("Microsoft RLE"), | |
163 | .type = AVMEDIA_TYPE_VIDEO, | |
164 | .id = AV_CODEC_ID_MSRLE, | |
165 | .priv_data_size = sizeof(MsrleContext), | |
166 | .init = msrle_decode_init, | |
167 | .close = msrle_decode_end, | |
168 | .decode = msrle_decode_frame, | |
169 | .capabilities = CODEC_CAP_DR1, | |
170 | }; |