Commit | Line | Data |
---|---|---|
a8a15e9d MM |
1 | /* |
2 | * Winnov WNV1 codec | |
3 | * Copyright (c) 2005 Konstantin Shishkov | |
4 | * | |
5 | * This library is free software; you can redistribute it and/or | |
6 | * modify it under the terms of the GNU Lesser General Public | |
7 | * License as published by the Free Software Foundation; either | |
8 | * version 2 of the License, or (at your option) any later version. | |
9 | * | |
10 | * This library is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | * Lesser General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU Lesser General Public | |
16 | * License along with this library; if not, write to the Free Software | |
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 | * | |
19 | */ | |
20 | ||
21 | /** | |
22 | * @file wnv1.c | |
23 | * Winnov WNV1 codec. | |
24 | */ | |
25 | ||
26 | #include "avcodec.h" | |
27 | #include "common.h" | |
28 | ||
29 | ||
30 | typedef struct WNV1Context{ | |
31 | AVCodecContext *avctx; | |
32 | AVFrame pic; | |
33 | ||
34 | int shift; | |
35 | /* bit buffer */ | |
36 | unsigned long bitbuf; | |
37 | int bits; | |
38 | uint8_t *buf; | |
39 | } WNV1Context; | |
40 | ||
41 | /* returns modified base_value */ | |
42 | static inline int wnv1_get_code(WNV1Context *w, int base_value) | |
43 | { | |
44 | int v = 0; | |
45 | ||
46 | if (w->bits < 16) { /* need to fill bit buffer */ | |
47 | w->bitbuf |= LE_16(w->buf) << w->bits; | |
48 | w->buf += 2; | |
49 | w->bits += 16; | |
50 | } | |
51 | ||
52 | /* escape code */ | |
53 | if ((w->bitbuf & 0xFF) == 0xFF) { | |
54 | w->bitbuf >>= 8; | |
55 | w->bits -= 8; | |
56 | if (w->bits < 16) { /* need to fill bit buffer */ | |
57 | w->bitbuf |= LE_16(w->buf) << w->bits; | |
58 | w->buf += 2; | |
59 | w->bits += 16; | |
60 | } | |
61 | v = w->bitbuf & (0xFF >> w->shift); | |
62 | w->bitbuf >>= 8 - w->shift; | |
63 | w->bits -= 8 - w->shift; | |
64 | return v << w->shift; | |
65 | } | |
66 | ||
67 | /* zero code */ | |
68 | if (!(w->bitbuf & 1)) { | |
69 | w->bitbuf >>= 1; | |
70 | w->bits--; | |
71 | return base_value; | |
72 | } | |
73 | ||
74 | /* reversed unary code and sign */ | |
75 | while (w->bits && w->bitbuf & 1) { | |
76 | w->bitbuf >>= 1; | |
77 | w->bits--; | |
78 | v++; | |
79 | } | |
80 | w->bitbuf >>= 1; | |
81 | w->bits--; | |
82 | if(w->bitbuf & 1) | |
83 | v = -v; | |
84 | w->bitbuf >>= 1; | |
85 | w->bits--; | |
86 | v <<= w->shift; | |
87 | return base_value + v; | |
88 | } | |
89 | ||
90 | static int decode_frame(AVCodecContext *avctx, | |
91 | void *data, int *data_size, | |
92 | uint8_t *buf, int buf_size) | |
93 | { | |
94 | WNV1Context * const l = avctx->priv_data; | |
95 | AVFrame * const p= (AVFrame*)&l->pic; | |
96 | unsigned char *Y,*U,*V; | |
97 | int i, j; | |
98 | int prev_y = 0, prev_u = 0, prev_v = 0; | |
99 | ||
100 | if(p->data[0]) | |
101 | avctx->release_buffer(avctx, p); | |
102 | ||
103 | p->reference = 0; | |
104 | if(avctx->get_buffer(avctx, p) < 0){ | |
105 | av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); | |
106 | return -1; | |
107 | } | |
108 | p->key_frame = 1; | |
109 | ||
110 | l->bitbuf = 0; | |
111 | l->bits = 0; | |
112 | l->buf = buf + 8; | |
113 | ||
114 | if (buf[2] >> 4 == 6) | |
115 | l->shift = 2; | |
116 | else { | |
117 | l->shift = 8 - (buf[2] >> 4); | |
118 | if (l->shift > 4) { | |
119 | av_log(avctx, AV_LOG_ERROR, "Unknown WNV1 frame header value %i, please upload file for study\n", buf[2] >> 4); | |
120 | l->shift = 4; | |
121 | } | |
122 | if (l->shift < 1) { | |
123 | av_log(avctx, AV_LOG_ERROR, "Unknown WNV1 frame header value %i, please upload file for study\n", buf[2] >> 4); | |
124 | l->shift = 1; | |
125 | } | |
126 | } | |
127 | ||
128 | Y = p->data[0]; | |
129 | U = p->data[1]; | |
130 | V = p->data[2]; | |
131 | for (j = 0; j < avctx->height; j++) { | |
132 | for (i = 0; i < avctx->width / 2; i++) { | |
133 | Y[i * 2] = wnv1_get_code(l, prev_y); | |
134 | prev_u = U[i] = wnv1_get_code(l, prev_u); | |
135 | prev_y = Y[(i * 2) + 1] = wnv1_get_code(l, Y[i * 2]); | |
136 | prev_v = V[i] = wnv1_get_code(l, prev_v); | |
137 | } | |
138 | Y += p->linesize[0]; | |
139 | U += p->linesize[1]; | |
140 | V += p->linesize[2]; | |
141 | } | |
142 | ||
143 | ||
144 | *data_size = sizeof(AVFrame); | |
145 | *(AVFrame*)data = l->pic; | |
146 | ||
147 | return buf_size; | |
148 | } | |
149 | ||
150 | static int decode_init(AVCodecContext *avctx){ | |
151 | WNV1Context * const l = avctx->priv_data; | |
152 | ||
153 | l->avctx = avctx; | |
154 | avctx->pix_fmt = PIX_FMT_YUV422P; | |
155 | ||
156 | return 0; | |
157 | } | |
158 | ||
159 | AVCodec wnv1_decoder = { | |
160 | "wnv1", | |
161 | CODEC_TYPE_VIDEO, | |
162 | CODEC_ID_WNV1, | |
163 | sizeof(WNV1Context), | |
164 | decode_init, | |
165 | NULL, | |
166 | NULL, | |
167 | decode_frame, | |
168 | CODEC_CAP_DR1, | |
169 | }; |