Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
6148 | serge | 1 | /* |
2 | * MxPEG decoder |
||
3 | * Copyright (c) 2011 Anatoly Nenashev |
||
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 | /** |
||
24 | * @file |
||
25 | * MxPEG decoder |
||
26 | */ |
||
27 | |||
28 | #include "internal.h" |
||
29 | #include "mjpeg.h" |
||
30 | #include "mjpegdec.h" |
||
31 | |||
32 | typedef struct MXpegDecodeContext { |
||
33 | MJpegDecodeContext jpg; |
||
34 | AVFrame picture[2]; /* pictures array */ |
||
35 | int picture_index; /* index of current picture */ |
||
36 | int got_sof_data; /* true if SOF data successfully parsed */ |
||
37 | int got_mxm_bitmask; /* true if MXM bitmask available */ |
||
38 | uint8_t *mxm_bitmask; /* bitmask buffer */ |
||
39 | unsigned bitmask_size; /* size of bitmask */ |
||
40 | int has_complete_frame; /* true if has complete frame */ |
||
41 | uint8_t *completion_bitmask; /* completion bitmask of macroblocks */ |
||
42 | unsigned mb_width, mb_height; /* size of picture in MB's from MXM header */ |
||
43 | } MXpegDecodeContext; |
||
44 | |||
45 | static av_cold int mxpeg_decode_init(AVCodecContext *avctx) |
||
46 | { |
||
47 | MXpegDecodeContext *s = avctx->priv_data; |
||
48 | |||
49 | s->jpg.picture_ptr = &s->picture[0]; |
||
50 | return ff_mjpeg_decode_init(avctx); |
||
51 | } |
||
52 | |||
53 | static int mxpeg_decode_app(MXpegDecodeContext *s, |
||
54 | const uint8_t *buf_ptr, int buf_size) |
||
55 | { |
||
56 | int len; |
||
57 | if (buf_size < 2) |
||
58 | return 0; |
||
59 | len = AV_RB16(buf_ptr); |
||
60 | skip_bits(&s->jpg.gb, 8*FFMIN(len,buf_size)); |
||
61 | |||
62 | return 0; |
||
63 | } |
||
64 | |||
65 | static int mxpeg_decode_mxm(MXpegDecodeContext *s, |
||
66 | const uint8_t *buf_ptr, int buf_size) |
||
67 | { |
||
68 | unsigned bitmask_size, mb_count; |
||
69 | int i; |
||
70 | |||
71 | s->mb_width = AV_RL16(buf_ptr+4); |
||
72 | s->mb_height = AV_RL16(buf_ptr+6); |
||
73 | mb_count = s->mb_width * s->mb_height; |
||
74 | |||
75 | bitmask_size = (mb_count + 7) >> 3; |
||
76 | if (bitmask_size > buf_size - 12) { |
||
77 | av_log(s->jpg.avctx, AV_LOG_ERROR, |
||
78 | "MXM bitmask is not complete\n"); |
||
79 | return AVERROR(EINVAL); |
||
80 | } |
||
81 | |||
82 | if (s->bitmask_size != bitmask_size) { |
||
83 | s->bitmask_size = 0; |
||
84 | av_freep(&s->mxm_bitmask); |
||
85 | s->mxm_bitmask = av_malloc(bitmask_size); |
||
86 | if (!s->mxm_bitmask) { |
||
87 | av_log(s->jpg.avctx, AV_LOG_ERROR, |
||
88 | "MXM bitmask memory allocation error\n"); |
||
89 | return AVERROR(ENOMEM); |
||
90 | } |
||
91 | |||
92 | av_freep(&s->completion_bitmask); |
||
93 | s->completion_bitmask = av_mallocz(bitmask_size); |
||
94 | if (!s->completion_bitmask) { |
||
95 | av_log(s->jpg.avctx, AV_LOG_ERROR, |
||
96 | "Completion bitmask memory allocation error\n"); |
||
97 | return AVERROR(ENOMEM); |
||
98 | } |
||
99 | |||
100 | s->bitmask_size = bitmask_size; |
||
101 | } |
||
102 | |||
103 | memcpy(s->mxm_bitmask, buf_ptr + 12, bitmask_size); |
||
104 | s->got_mxm_bitmask = 1; |
||
105 | |||
106 | if (!s->has_complete_frame) { |
||
107 | uint8_t completion_check = 0xFF; |
||
108 | for (i = 0; i < bitmask_size; ++i) { |
||
109 | s->completion_bitmask[i] |= s->mxm_bitmask[i]; |
||
110 | completion_check &= s->completion_bitmask[i]; |
||
111 | } |
||
112 | s->has_complete_frame = !(completion_check ^ 0xFF); |
||
113 | } |
||
114 | |||
115 | return 0; |
||
116 | } |
||
117 | |||
118 | static int mxpeg_decode_com(MXpegDecodeContext *s, |
||
119 | const uint8_t *buf_ptr, int buf_size) |
||
120 | { |
||
121 | int len, ret = 0; |
||
122 | if (buf_size < 2) |
||
123 | return 0; |
||
124 | len = AV_RB16(buf_ptr); |
||
125 | if (len > 14 && len <= buf_size && !strncmp(buf_ptr + 2, "MXM", 3)) { |
||
126 | ret = mxpeg_decode_mxm(s, buf_ptr + 2, len - 2); |
||
127 | } |
||
128 | skip_bits(&s->jpg.gb, 8*FFMIN(len,buf_size)); |
||
129 | |||
130 | return ret; |
||
131 | } |
||
132 | |||
133 | static int mxpeg_check_dimensions(MXpegDecodeContext *s, MJpegDecodeContext *jpg, |
||
134 | AVFrame *reference_ptr) |
||
135 | { |
||
136 | if ((jpg->width + 0x0F)>>4 != s->mb_width || |
||
137 | (jpg->height + 0x0F)>>4 != s->mb_height) { |
||
138 | av_log(jpg->avctx, AV_LOG_ERROR, |
||
139 | "Picture dimensions stored in SOF and MXM mismatch\n"); |
||
140 | return AVERROR(EINVAL); |
||
141 | } |
||
142 | |||
143 | if (reference_ptr->data[0]) { |
||
144 | int i; |
||
145 | for (i = 0; i < MAX_COMPONENTS; ++i) { |
||
146 | if ( (!reference_ptr->data[i] ^ !jpg->picture_ptr->data[i]) || |
||
147 | reference_ptr->linesize[i] != jpg->picture_ptr->linesize[i]) { |
||
148 | av_log(jpg->avctx, AV_LOG_ERROR, |
||
149 | "Dimensions of current and reference picture mismatch\n"); |
||
150 | return AVERROR(EINVAL); |
||
151 | } |
||
152 | } |
||
153 | } |
||
154 | |||
155 | return 0; |
||
156 | } |
||
157 | |||
158 | static int mxpeg_decode_frame(AVCodecContext *avctx, |
||
159 | void *data, int *got_frame, |
||
160 | AVPacket *avpkt) |
||
161 | { |
||
162 | const uint8_t *buf = avpkt->data; |
||
163 | int buf_size = avpkt->size; |
||
164 | MXpegDecodeContext *s = avctx->priv_data; |
||
165 | MJpegDecodeContext *jpg = &s->jpg; |
||
166 | const uint8_t *buf_end, *buf_ptr; |
||
167 | const uint8_t *unescaped_buf_ptr; |
||
168 | int unescaped_buf_size; |
||
169 | int start_code; |
||
170 | int ret; |
||
171 | |||
172 | buf_ptr = buf; |
||
173 | buf_end = buf + buf_size; |
||
174 | jpg->got_picture = 0; |
||
175 | s->got_mxm_bitmask = 0; |
||
176 | while (buf_ptr < buf_end) { |
||
177 | start_code = ff_mjpeg_find_marker(jpg, &buf_ptr, buf_end, |
||
178 | &unescaped_buf_ptr, &unescaped_buf_size); |
||
179 | if (start_code < 0) |
||
180 | goto the_end; |
||
181 | { |
||
182 | init_get_bits(&jpg->gb, unescaped_buf_ptr, unescaped_buf_size*8); |
||
183 | |||
184 | if (start_code >= APP0 && start_code <= APP15) { |
||
185 | mxpeg_decode_app(s, unescaped_buf_ptr, unescaped_buf_size); |
||
186 | } |
||
187 | |||
188 | switch (start_code) { |
||
189 | case SOI: |
||
190 | if (jpg->got_picture) //emulating EOI |
||
191 | goto the_end; |
||
192 | break; |
||
193 | case EOI: |
||
194 | goto the_end; |
||
195 | case DQT: |
||
196 | ret = ff_mjpeg_decode_dqt(jpg); |
||
197 | if (ret < 0) { |
||
198 | av_log(avctx, AV_LOG_ERROR, |
||
199 | "quantization table decode error\n"); |
||
200 | return ret; |
||
201 | } |
||
202 | break; |
||
203 | case DHT: |
||
204 | ret = ff_mjpeg_decode_dht(jpg); |
||
205 | if (ret < 0) { |
||
206 | av_log(avctx, AV_LOG_ERROR, |
||
207 | "huffman table decode error\n"); |
||
208 | return ret; |
||
209 | } |
||
210 | break; |
||
211 | case COM: |
||
212 | ret = mxpeg_decode_com(s, unescaped_buf_ptr, |
||
213 | unescaped_buf_size); |
||
214 | if (ret < 0) |
||
215 | return ret; |
||
216 | break; |
||
217 | case SOF0: |
||
218 | s->got_sof_data = 0; |
||
219 | ret = ff_mjpeg_decode_sof(jpg); |
||
220 | if (ret < 0) { |
||
221 | av_log(avctx, AV_LOG_ERROR, |
||
222 | "SOF data decode error\n"); |
||
223 | return ret; |
||
224 | } |
||
225 | if (jpg->interlaced) { |
||
226 | av_log(avctx, AV_LOG_ERROR, |
||
227 | "Interlaced mode not supported in MxPEG\n"); |
||
228 | return AVERROR(EINVAL); |
||
229 | } |
||
230 | s->got_sof_data = 1; |
||
231 | break; |
||
232 | case SOS: |
||
233 | if (!s->got_sof_data) { |
||
234 | av_log(avctx, AV_LOG_WARNING, |
||
235 | "Can not process SOS without SOF data, skipping\n"); |
||
236 | break; |
||
237 | } |
||
238 | if (!jpg->got_picture) { |
||
239 | if (jpg->first_picture) { |
||
240 | av_log(avctx, AV_LOG_WARNING, |
||
241 | "First picture has no SOF, skipping\n"); |
||
242 | break; |
||
243 | } |
||
244 | if (!s->got_mxm_bitmask){ |
||
245 | av_log(avctx, AV_LOG_WARNING, |
||
246 | "Non-key frame has no MXM, skipping\n"); |
||
247 | break; |
||
248 | } |
||
249 | /* use stored SOF data to allocate current picture */ |
||
250 | av_frame_unref(jpg->picture_ptr); |
||
251 | if ((ret = ff_get_buffer(avctx, jpg->picture_ptr, |
||
252 | AV_GET_BUFFER_FLAG_REF)) < 0) |
||
253 | return ret; |
||
254 | jpg->picture_ptr->pict_type = AV_PICTURE_TYPE_P; |
||
255 | jpg->picture_ptr->key_frame = 0; |
||
256 | jpg->got_picture = 1; |
||
257 | } else { |
||
258 | jpg->picture_ptr->pict_type = AV_PICTURE_TYPE_I; |
||
259 | jpg->picture_ptr->key_frame = 1; |
||
260 | } |
||
261 | |||
262 | if (s->got_mxm_bitmask) { |
||
263 | AVFrame *reference_ptr = &s->picture[s->picture_index ^ 1]; |
||
264 | if (mxpeg_check_dimensions(s, jpg, reference_ptr) < 0) |
||
265 | break; |
||
266 | |||
267 | /* allocate dummy reference picture if needed */ |
||
268 | if (!reference_ptr->data[0] && |
||
269 | (ret = ff_get_buffer(avctx, reference_ptr, |
||
270 | AV_GET_BUFFER_FLAG_REF)) < 0) |
||
271 | return ret; |
||
272 | |||
273 | ret = ff_mjpeg_decode_sos(jpg, s->mxm_bitmask, reference_ptr); |
||
274 | if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE)) |
||
275 | return ret; |
||
276 | } else { |
||
277 | ret = ff_mjpeg_decode_sos(jpg, NULL, NULL); |
||
278 | if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE)) |
||
279 | return ret; |
||
280 | } |
||
281 | |||
282 | break; |
||
283 | } |
||
284 | |||
285 | buf_ptr += (get_bits_count(&jpg->gb)+7) >> 3; |
||
286 | } |
||
287 | |||
288 | } |
||
289 | |||
290 | the_end: |
||
291 | if (jpg->got_picture) { |
||
292 | int ret = av_frame_ref(data, jpg->picture_ptr); |
||
293 | if (ret < 0) |
||
294 | return ret; |
||
295 | *got_frame = 1; |
||
296 | |||
297 | s->picture_index ^= 1; |
||
298 | jpg->picture_ptr = &s->picture[s->picture_index]; |
||
299 | |||
300 | if (!s->has_complete_frame) { |
||
301 | if (!s->got_mxm_bitmask) |
||
302 | s->has_complete_frame = 1; |
||
303 | else |
||
304 | *got_frame = 0; |
||
305 | } |
||
306 | } |
||
307 | |||
308 | return buf_ptr - buf; |
||
309 | } |
||
310 | |||
311 | static av_cold int mxpeg_decode_end(AVCodecContext *avctx) |
||
312 | { |
||
313 | MXpegDecodeContext *s = avctx->priv_data; |
||
314 | MJpegDecodeContext *jpg = &s->jpg; |
||
315 | int i; |
||
316 | |||
317 | jpg->picture_ptr = NULL; |
||
318 | ff_mjpeg_decode_end(avctx); |
||
319 | |||
320 | for (i = 0; i < 2; ++i) |
||
321 | av_frame_unref(&s->picture[i]); |
||
322 | |||
323 | av_freep(&s->mxm_bitmask); |
||
324 | av_freep(&s->completion_bitmask); |
||
325 | |||
326 | return 0; |
||
327 | } |
||
328 | |||
329 | AVCodec ff_mxpeg_decoder = { |
||
330 | .name = "mxpeg", |
||
331 | .long_name = NULL_IF_CONFIG_SMALL("Mobotix MxPEG video"), |
||
332 | .type = AVMEDIA_TYPE_VIDEO, |
||
333 | .id = AV_CODEC_ID_MXPEG, |
||
334 | .priv_data_size = sizeof(MXpegDecodeContext), |
||
335 | .init = mxpeg_decode_init, |
||
336 | .close = mxpeg_decode_end, |
||
337 | .decode = mxpeg_decode_frame, |
||
338 | .capabilities = CODEC_CAP_DR1, |
||
339 | .max_lowres = 3, |
||
340 | };>>>>>>>>>>>=>>>>=>>>> |