Mercurial > libavcodec.hg
annotate idcinvideo.c @ 7352:c2318e551ff5 libavcodec
When picking a "high utility centroid" do not pick one
that has no corresponding points. Not only it is the
worst possible pick, but also the code was written
without this case in mind.
author | vitor |
---|---|
date | Wed, 23 Jul 2008 03:55:37 +0000 |
parents | e943e1409077 |
children | bc36a075bf35 |
rev | line source |
---|---|
1498 | 1 /* |
6812
0d01bae8d207
cosmetics: s/Id/id/ in libavcodec where Id refers to id Software.
diego
parents:
6712
diff
changeset
|
2 * id Quake II CIN Video Decoder |
1498 | 3 * Copyright (C) 2003 the ffmpeg project |
4 * | |
3947
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3036
diff
changeset
|
5 * This file is part of FFmpeg. |
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3036
diff
changeset
|
6 * |
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3036
diff
changeset
|
7 * FFmpeg is free software; you can redistribute it and/or |
1498 | 8 * modify it under the terms of the GNU Lesser General Public |
9 * License as published by the Free Software Foundation; either | |
3947
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3036
diff
changeset
|
10 * version 2.1 of the License, or (at your option) any later version. |
1498 | 11 * |
3947
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3036
diff
changeset
|
12 * FFmpeg is distributed in the hope that it will be useful, |
1498 | 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 | |
3947
c8c591fe26f8
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
3036
diff
changeset
|
18 * License along with FFmpeg; if not, write to the Free Software |
3036
0b546eab515d
Update licensing information: The FSF changed postal address.
diego
parents:
2508
diff
changeset
|
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
1498 | 20 */ |
21 | |
22 /** | |
23 * @file idcinvideo.c | |
6812
0d01bae8d207
cosmetics: s/Id/id/ in libavcodec where Id refers to id Software.
diego
parents:
6712
diff
changeset
|
24 * id Quake II Cin Video Decoder by Dr. Tim Ferguson |
0d01bae8d207
cosmetics: s/Id/id/ in libavcodec where Id refers to id Software.
diego
parents:
6712
diff
changeset
|
25 * For more information about the id CIN format, visit: |
1498 | 26 * http://www.csse.monash.edu.au/~timf/ |
27 * | |
1499 | 28 * This video decoder outputs PAL8 colorspace data. Interacting with this |
29 * decoder is a little involved. During initialization, the demuxer must | |
30 * transmit the 65536-byte Huffman table(s) to the decoder via extradata. | |
31 * Then, whenever a palette change is encountered while demuxing the file, | |
32 * the demuxer must use the same extradata space to transmit an | |
33 * AVPaletteControl structure. | |
1498 | 34 * |
6812
0d01bae8d207
cosmetics: s/Id/id/ in libavcodec where Id refers to id Software.
diego
parents:
6712
diff
changeset
|
35 * id CIN video is purely Huffman-coded, intraframe-only codec. It achieves |
1498 | 36 * a little more compression by exploiting the fact that adjacent pixels |
37 * tend to be similar. | |
38 * | |
39 * Note that this decoder could use ffmpeg's optimized VLC facilities | |
40 * rather than naive, tree-based Huffman decoding. However, there are 256 | |
41 * Huffman tables. Plus, the VLC bit coding order is right -> left instead | |
42 * or left -> right, so all of the bits would have to be reversed. Further, | |
43 * the original Quake II implementation likely used a similar naive | |
44 * decoding algorithm and it worked fine on much lower spec machines. | |
45 */ | |
46 | |
47 #include <stdio.h> | |
48 #include <stdlib.h> | |
49 #include <string.h> | |
50 #include <unistd.h> | |
51 | |
52 #include "avcodec.h" | |
53 | |
54 #define HUFFMAN_TABLE_SIZE 64 * 1024 | |
55 #define HUF_TOKENS 256 | |
56 #define PALETTE_COUNT 256 | |
57 | |
58 typedef struct | |
59 { | |
60 int count; | |
61 unsigned char used; | |
62 int children[2]; | |
63 } hnode_t; | |
64 | |
65 typedef struct IdcinContext { | |
66 | |
67 AVCodecContext *avctx; | |
68 AVFrame frame; | |
69 | |
6218 | 70 const unsigned char *buf; |
1498 | 71 int size; |
72 | |
73 hnode_t huff_nodes[256][HUF_TOKENS*2]; | |
74 int num_huff_nodes[256]; | |
75 | |
76 } IdcinContext; | |
77 | |
78 /* | |
79 * Find the lowest probability node in a Huffman table, and mark it as | |
80 * being assigned to a higher probability. | |
81 * Returns the node index of the lowest unused node, or -1 if all nodes | |
82 * are used. | |
83 */ | |
84 static int huff_smallest_node(hnode_t *hnodes, int num_hnodes) { | |
85 int i; | |
86 int best, best_node; | |
87 | |
88 best = 99999999; | |
89 best_node = -1; | |
90 for(i = 0; i < num_hnodes; i++) { | |
91 if(hnodes[i].used) | |
92 continue; | |
93 if(!hnodes[i].count) | |
94 continue; | |
95 if(hnodes[i].count < best) { | |
96 best = hnodes[i].count; | |
97 best_node = i; | |
98 } | |
99 } | |
100 | |
101 if(best_node == -1) | |
102 return -1; | |
103 hnodes[best_node].used = 1; | |
104 return best_node; | |
105 } | |
106 | |
107 /* | |
108 * Build the Huffman tree using the generated/loaded probabilities histogram. | |
109 * | |
110 * On completion: | |
111 * huff_nodes[prev][i < HUF_TOKENS] - are the nodes at the base of the tree. | |
112 * huff_nodes[prev][i >= HUF_TOKENS] - are used to construct the tree. | |
113 * num_huff_nodes[prev] - contains the index to the root node of the tree. | |
114 * That is: huff_nodes[prev][num_huff_nodes[prev]] is the root node. | |
115 */ | |
6517
48759bfbd073
Apply 'cold' attribute to init/uninit functions in libavcodec
zuxy
parents:
6484
diff
changeset
|
116 static av_cold void huff_build_tree(IdcinContext *s, int prev) { |
1498 | 117 hnode_t *node, *hnodes; |
118 int num_hnodes, i; | |
119 | |
120 num_hnodes = HUF_TOKENS; | |
121 hnodes = s->huff_nodes[prev]; | |
122 for(i = 0; i < HUF_TOKENS * 2; i++) | |
123 hnodes[i].used = 0; | |
124 | |
125 while (1) { | |
126 node = &hnodes[num_hnodes]; /* next free node */ | |
127 | |
128 /* pick two lowest counts */ | |
129 node->children[0] = huff_smallest_node(hnodes, num_hnodes); | |
130 if(node->children[0] == -1) | |
131 break; /* reached the root node */ | |
132 | |
133 node->children[1] = huff_smallest_node(hnodes, num_hnodes); | |
134 if(node->children[1] == -1) | |
135 break; /* reached the root node */ | |
136 | |
137 /* combine nodes probability for new node */ | |
138 node->count = hnodes[node->children[0]].count + | |
139 hnodes[node->children[1]].count; | |
140 num_hnodes++; | |
141 } | |
142 | |
143 s->num_huff_nodes[prev] = num_hnodes - 1; | |
144 } | |
145 | |
6517
48759bfbd073
Apply 'cold' attribute to init/uninit functions in libavcodec
zuxy
parents:
6484
diff
changeset
|
146 static av_cold int idcin_decode_init(AVCodecContext *avctx) |
1498 | 147 { |
4827 | 148 IdcinContext *s = avctx->priv_data; |
1498 | 149 int i, j, histogram_index = 0; |
150 unsigned char *histograms; | |
151 | |
152 s->avctx = avctx; | |
153 avctx->pix_fmt = PIX_FMT_PAL8; | |
154 | |
155 /* make sure the Huffman tables make it */ | |
156 if (s->avctx->extradata_size != HUFFMAN_TABLE_SIZE) { | |
6812
0d01bae8d207
cosmetics: s/Id/id/ in libavcodec where Id refers to id Software.
diego
parents:
6712
diff
changeset
|
157 av_log(s->avctx, AV_LOG_ERROR, " id CIN video: expected extradata size of %d\n", HUFFMAN_TABLE_SIZE); |
1498 | 158 return -1; |
159 } | |
160 | |
161 /* build the 256 Huffman decode trees */ | |
162 histograms = (unsigned char *)s->avctx->extradata; | |
163 for (i = 0; i < 256; i++) { | |
164 for(j = 0; j < HUF_TOKENS; j++) | |
165 s->huff_nodes[i][j].count = histograms[histogram_index++]; | |
166 huff_build_tree(s, i); | |
167 } | |
168 | |
169 s->frame.data[0] = NULL; | |
170 | |
171 return 0; | |
172 } | |
173 | |
174 static void idcin_decode_vlcs(IdcinContext *s) | |
175 { | |
176 hnode_t *hnodes; | |
177 long x, y; | |
178 int prev; | |
179 unsigned char v = 0; | |
180 int bit_pos, node_num, dat_pos; | |
181 | |
182 prev = bit_pos = dat_pos = 0; | |
183 for (y = 0; y < (s->frame.linesize[0] * s->avctx->height); | |
184 y += s->frame.linesize[0]) { | |
185 for (x = y; x < y + s->avctx->width; x++) { | |
186 node_num = s->num_huff_nodes[prev]; | |
187 hnodes = s->huff_nodes[prev]; | |
188 | |
189 while(node_num >= HUF_TOKENS) { | |
190 if(!bit_pos) { | |
2508 | 191 if(dat_pos >= s->size) { |
1598
932d306bf1dc
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
1585
diff
changeset
|
192 av_log(s->avctx, AV_LOG_ERROR, "Huffman decode error.\n"); |
1498 | 193 return; |
194 } | |
195 bit_pos = 8; | |
196 v = s->buf[dat_pos++]; | |
197 } | |
198 | |
199 node_num = hnodes[node_num].children[v & 0x01]; | |
200 v = v >> 1; | |
201 bit_pos--; | |
202 } | |
203 | |
204 s->frame.data[0][x] = node_num; | |
205 prev = node_num; | |
206 } | |
207 } | |
208 } | |
209 | |
210 static int idcin_decode_frame(AVCodecContext *avctx, | |
211 void *data, int *data_size, | |
6218 | 212 const uint8_t *buf, int buf_size) |
1498 | 213 { |
4827 | 214 IdcinContext *s = avctx->priv_data; |
1585
6b224ca24033
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
1499
diff
changeset
|
215 AVPaletteControl *palette_control = avctx->palctrl; |
1498 | 216 |
217 s->buf = buf; | |
218 s->size = buf_size; | |
219 | |
220 if (s->frame.data[0]) | |
221 avctx->release_buffer(avctx, &s->frame); | |
222 | |
223 if (avctx->get_buffer(avctx, &s->frame)) { | |
6812
0d01bae8d207
cosmetics: s/Id/id/ in libavcodec where Id refers to id Software.
diego
parents:
6712
diff
changeset
|
224 av_log(avctx, AV_LOG_ERROR, " id CIN Video: get_buffer() failed\n"); |
1498 | 225 return -1; |
226 } | |
227 | |
228 idcin_decode_vlcs(s); | |
229 | |
230 /* make the palette available on the way out */ | |
1585
6b224ca24033
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
1499
diff
changeset
|
231 memcpy(s->frame.data[1], palette_control->palette, PALETTE_COUNT * 4); |
6b224ca24033
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
1499
diff
changeset
|
232 /* If palette changed inform application*/ |
6b224ca24033
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
1499
diff
changeset
|
233 if (palette_control->palette_changed) { |
6b224ca24033
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
1499
diff
changeset
|
234 palette_control->palette_changed = 0; |
6b224ca24033
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
1499
diff
changeset
|
235 s->frame.palette_has_changed = 1; |
6b224ca24033
revised palette API, courtesy of Roberto Togni (rtogni at freemail.it)
melanson
parents:
1499
diff
changeset
|
236 } |
1498 | 237 |
238 *data_size = sizeof(AVFrame); | |
239 *(AVFrame*)data = s->frame; | |
240 | |
241 /* report that the buffer was completely consumed */ | |
242 return buf_size; | |
243 } | |
244 | |
6517
48759bfbd073
Apply 'cold' attribute to init/uninit functions in libavcodec
zuxy
parents:
6484
diff
changeset
|
245 static av_cold int idcin_decode_end(AVCodecContext *avctx) |
1498 | 246 { |
4827 | 247 IdcinContext *s = avctx->priv_data; |
1498 | 248 |
249 if (s->frame.data[0]) | |
250 avctx->release_buffer(avctx, &s->frame); | |
251 | |
252 return 0; | |
253 } | |
254 | |
255 AVCodec idcin_decoder = { | |
256 "idcinvideo", | |
257 CODEC_TYPE_VIDEO, | |
258 CODEC_ID_IDCIN, | |
259 sizeof(IdcinContext), | |
260 idcin_decode_init, | |
261 NULL, | |
262 idcin_decode_end, | |
263 idcin_decode_frame, | |
264 CODEC_CAP_DR1, | |
7040
e943e1409077
Make AVCodec long_names definition conditional depending on CONFIG_SMALL.
stefano
parents:
6812
diff
changeset
|
265 .long_name = NULL_IF_CONFIG_SMALL("id Quake II CIN video"), |
1498 | 266 }; |
267 |