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