yading@10
|
1 /*
|
yading@10
|
2 * Quicktime Planar RGB (8BPS) Video Decoder
|
yading@10
|
3 * Copyright (C) 2003 Roberto Togni
|
yading@10
|
4 *
|
yading@10
|
5 * This file is part of FFmpeg.
|
yading@10
|
6 *
|
yading@10
|
7 * FFmpeg is free software; you can redistribute it and/or
|
yading@10
|
8 * modify it under the terms of the GNU Lesser General Public
|
yading@10
|
9 * License as published by the Free Software Foundation; either
|
yading@10
|
10 * version 2.1 of the License, or (at your option) any later version.
|
yading@10
|
11 *
|
yading@10
|
12 * FFmpeg is distributed in the hope that it will be useful,
|
yading@10
|
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
yading@10
|
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
yading@10
|
15 * Lesser General Public License for more details.
|
yading@10
|
16 *
|
yading@10
|
17 * You should have received a copy of the GNU Lesser General Public
|
yading@10
|
18 * License along with FFmpeg; if not, write to the Free Software
|
yading@10
|
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
yading@10
|
20 */
|
yading@10
|
21
|
yading@10
|
22 /**
|
yading@10
|
23 * @file
|
yading@10
|
24 * QT 8BPS Video Decoder by Roberto Togni
|
yading@10
|
25 * For more information about the 8BPS format, visit:
|
yading@10
|
26 * http://www.pcisys.net/~melanson/codecs/
|
yading@10
|
27 *
|
yading@10
|
28 * Supports: PAL8 (RGB 8bpp, paletted)
|
yading@10
|
29 * : BGR24 (RGB 24bpp) (can also output it as RGB32)
|
yading@10
|
30 * : RGB32 (RGB 32bpp, 4th plane is alpha)
|
yading@10
|
31 *
|
yading@10
|
32 */
|
yading@10
|
33
|
yading@10
|
34 #include <stdio.h>
|
yading@10
|
35 #include <stdlib.h>
|
yading@10
|
36 #include <string.h>
|
yading@10
|
37
|
yading@10
|
38 #include "libavutil/internal.h"
|
yading@10
|
39 #include "libavutil/intreadwrite.h"
|
yading@10
|
40 #include "avcodec.h"
|
yading@10
|
41 #include "internal.h"
|
yading@10
|
42
|
yading@10
|
43
|
yading@10
|
44 static const enum AVPixelFormat pixfmt_rgb24[] = {
|
yading@10
|
45 AV_PIX_FMT_BGR24, AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE };
|
yading@10
|
46
|
yading@10
|
47 typedef struct EightBpsContext {
|
yading@10
|
48 AVCodecContext *avctx;
|
yading@10
|
49
|
yading@10
|
50 unsigned char planes;
|
yading@10
|
51 unsigned char planemap[4];
|
yading@10
|
52
|
yading@10
|
53 uint32_t pal[256];
|
yading@10
|
54 } EightBpsContext;
|
yading@10
|
55
|
yading@10
|
56 static int decode_frame(AVCodecContext *avctx, void *data,
|
yading@10
|
57 int *got_frame, AVPacket *avpkt)
|
yading@10
|
58 {
|
yading@10
|
59 AVFrame *frame = data;
|
yading@10
|
60 const uint8_t *buf = avpkt->data;
|
yading@10
|
61 int buf_size = avpkt->size;
|
yading@10
|
62 EightBpsContext * const c = avctx->priv_data;
|
yading@10
|
63 const unsigned char *encoded = buf;
|
yading@10
|
64 unsigned char *pixptr, *pixptr_end;
|
yading@10
|
65 unsigned int height = avctx->height; // Real image height
|
yading@10
|
66 unsigned int dlen, p, row;
|
yading@10
|
67 const unsigned char *lp, *dp;
|
yading@10
|
68 unsigned char count;
|
yading@10
|
69 unsigned int planes = c->planes;
|
yading@10
|
70 unsigned char *planemap = c->planemap;
|
yading@10
|
71 int ret;
|
yading@10
|
72
|
yading@10
|
73 if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
|
yading@10
|
74 return ret;
|
yading@10
|
75
|
yading@10
|
76 /* Set data pointer after line lengths */
|
yading@10
|
77 dp = encoded + planes * (height << 1);
|
yading@10
|
78
|
yading@10
|
79 for (p = 0; p < planes; p++) {
|
yading@10
|
80 /* Lines length pointer for this plane */
|
yading@10
|
81 lp = encoded + p * (height << 1);
|
yading@10
|
82
|
yading@10
|
83 /* Decode a plane */
|
yading@10
|
84 for (row = 0; row < height; row++) {
|
yading@10
|
85 pixptr = frame->data[0] + row * frame->linesize[0] + planemap[p];
|
yading@10
|
86 pixptr_end = pixptr + frame->linesize[0];
|
yading@10
|
87 if(lp - encoded + row*2 + 1 >= buf_size)
|
yading@10
|
88 return -1;
|
yading@10
|
89 dlen = av_be2ne16(*(const unsigned short *)(lp + row * 2));
|
yading@10
|
90 /* Decode a row of this plane */
|
yading@10
|
91 while (dlen > 0) {
|
yading@10
|
92 if (dp + 1 >= buf + buf_size)
|
yading@10
|
93 return AVERROR_INVALIDDATA;
|
yading@10
|
94 if ((count = *dp++) <= 127) {
|
yading@10
|
95 count++;
|
yading@10
|
96 dlen -= count + 1;
|
yading@10
|
97 if (pixptr + count * planes > pixptr_end)
|
yading@10
|
98 break;
|
yading@10
|
99 if (dp + count > buf + buf_size)
|
yading@10
|
100 return AVERROR_INVALIDDATA;
|
yading@10
|
101 while (count--) {
|
yading@10
|
102 *pixptr = *dp++;
|
yading@10
|
103 pixptr += planes;
|
yading@10
|
104 }
|
yading@10
|
105 } else {
|
yading@10
|
106 count = 257 - count;
|
yading@10
|
107 if (pixptr + count * planes > pixptr_end)
|
yading@10
|
108 break;
|
yading@10
|
109 while (count--) {
|
yading@10
|
110 *pixptr = *dp;
|
yading@10
|
111 pixptr += planes;
|
yading@10
|
112 }
|
yading@10
|
113 dp++;
|
yading@10
|
114 dlen -= 2;
|
yading@10
|
115 }
|
yading@10
|
116 }
|
yading@10
|
117 }
|
yading@10
|
118 }
|
yading@10
|
119
|
yading@10
|
120 if (avctx->bits_per_coded_sample <= 8) {
|
yading@10
|
121 const uint8_t *pal = av_packet_get_side_data(avpkt,
|
yading@10
|
122 AV_PKT_DATA_PALETTE,
|
yading@10
|
123 NULL);
|
yading@10
|
124 if (pal) {
|
yading@10
|
125 frame->palette_has_changed = 1;
|
yading@10
|
126 memcpy(c->pal, pal, AVPALETTE_SIZE);
|
yading@10
|
127 }
|
yading@10
|
128
|
yading@10
|
129 memcpy (frame->data[1], c->pal, AVPALETTE_SIZE);
|
yading@10
|
130 }
|
yading@10
|
131
|
yading@10
|
132 *got_frame = 1;
|
yading@10
|
133
|
yading@10
|
134 /* always report that the buffer was completely consumed */
|
yading@10
|
135 return buf_size;
|
yading@10
|
136 }
|
yading@10
|
137
|
yading@10
|
138 static av_cold int decode_init(AVCodecContext *avctx)
|
yading@10
|
139 {
|
yading@10
|
140 EightBpsContext * const c = avctx->priv_data;
|
yading@10
|
141
|
yading@10
|
142 c->avctx = avctx;
|
yading@10
|
143
|
yading@10
|
144 switch (avctx->bits_per_coded_sample) {
|
yading@10
|
145 case 8:
|
yading@10
|
146 avctx->pix_fmt = AV_PIX_FMT_PAL8;
|
yading@10
|
147 c->planes = 1;
|
yading@10
|
148 c->planemap[0] = 0; // 1st plane is palette indexes
|
yading@10
|
149 break;
|
yading@10
|
150 case 24:
|
yading@10
|
151 avctx->pix_fmt = avctx->get_format(avctx, pixfmt_rgb24);
|
yading@10
|
152 c->planes = 3;
|
yading@10
|
153 c->planemap[0] = 2; // 1st plane is red
|
yading@10
|
154 c->planemap[1] = 1; // 2nd plane is green
|
yading@10
|
155 c->planemap[2] = 0; // 3rd plane is blue
|
yading@10
|
156 break;
|
yading@10
|
157 case 32:
|
yading@10
|
158 avctx->pix_fmt = AV_PIX_FMT_RGB32;
|
yading@10
|
159 c->planes = 4;
|
yading@10
|
160 #if HAVE_BIGENDIAN
|
yading@10
|
161 c->planemap[0] = 1; // 1st plane is red
|
yading@10
|
162 c->planemap[1] = 2; // 2nd plane is green
|
yading@10
|
163 c->planemap[2] = 3; // 3rd plane is blue
|
yading@10
|
164 c->planemap[3] = 0; // 4th plane is alpha
|
yading@10
|
165 #else
|
yading@10
|
166 c->planemap[0] = 2; // 1st plane is red
|
yading@10
|
167 c->planemap[1] = 1; // 2nd plane is green
|
yading@10
|
168 c->planemap[2] = 0; // 3rd plane is blue
|
yading@10
|
169 c->planemap[3] = 3; // 4th plane is alpha
|
yading@10
|
170 #endif
|
yading@10
|
171 break;
|
yading@10
|
172 default:
|
yading@10
|
173 av_log(avctx, AV_LOG_ERROR, "Error: Unsupported color depth: %u.\n",
|
yading@10
|
174 avctx->bits_per_coded_sample);
|
yading@10
|
175 return AVERROR_INVALIDDATA;
|
yading@10
|
176 }
|
yading@10
|
177
|
yading@10
|
178 return 0;
|
yading@10
|
179 }
|
yading@10
|
180
|
yading@10
|
181 AVCodec ff_eightbps_decoder = {
|
yading@10
|
182 .name = "8bps",
|
yading@10
|
183 .type = AVMEDIA_TYPE_VIDEO,
|
yading@10
|
184 .id = AV_CODEC_ID_8BPS,
|
yading@10
|
185 .priv_data_size = sizeof(EightBpsContext),
|
yading@10
|
186 .init = decode_init,
|
yading@10
|
187 .decode = decode_frame,
|
yading@10
|
188 .capabilities = CODEC_CAP_DR1,
|
yading@10
|
189 .long_name = NULL_IF_CONFIG_SMALL("QuickTime 8BPS video"),
|
yading@10
|
190 };
|