• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavcodec/mxpegdec.c

Go to the documentation of this file.
00001 /*
00002  * MxPEG decoder
00003  * Copyright (c) 2011 Anatoly Nenashev
00004  *
00005  * This file is part of FFmpeg.
00006  *
00007  * FFmpeg is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * FFmpeg is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with FFmpeg; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00022 
00028 #include "mjpeg.h"
00029 #include "mjpegdec.h"
00030 
00031 typedef struct MXpegDecodeContext {
00032     MJpegDecodeContext jpg;
00033     AVFrame picture[2]; /* pictures array */
00034     int picture_index; /* index of current picture */
00035     int got_sof_data; /* true if SOF data successfully parsed */
00036     int got_mxm_bitmask; /* true if MXM bitmask available */
00037     uint8_t *mxm_bitmask; /* bitmask buffer */
00038     unsigned bitmask_size; /* size of bitmask */
00039     int has_complete_frame; /* true if has complete frame */
00040     uint8_t *completion_bitmask; /* completion bitmask of macroblocks */
00041     unsigned mb_width, mb_height; /* size of picture in MB's from MXM header */
00042 } MXpegDecodeContext;
00043 
00044 static av_cold int mxpeg_decode_init(AVCodecContext *avctx)
00045 {
00046     MXpegDecodeContext *s = avctx->priv_data;
00047 
00048     s->picture[0].reference = s->picture[1].reference = 3;
00049     s->jpg.picture_ptr      = &s->picture[0];
00050     return ff_mjpeg_decode_init(avctx);
00051 }
00052 
00053 static int mxpeg_decode_app(MXpegDecodeContext *s,
00054                             const uint8_t *buf_ptr, int buf_size)
00055 {
00056     int len;
00057     if (buf_size < 2)
00058         return 0;
00059     len = AV_RB16(buf_ptr);
00060     skip_bits(&s->jpg.gb, 8*FFMIN(len,buf_size));
00061 
00062     return 0;
00063 }
00064 
00065 static int mxpeg_decode_mxm(MXpegDecodeContext *s,
00066                             const uint8_t *buf_ptr, int buf_size)
00067 {
00068     unsigned bitmask_size, mb_count;
00069     int i;
00070 
00071     s->mb_width  = AV_RL16(buf_ptr+4);
00072     s->mb_height = AV_RL16(buf_ptr+6);
00073     mb_count = s->mb_width * s->mb_height;
00074 
00075     bitmask_size = (mb_count + 7) >> 3;
00076     if (bitmask_size > buf_size - 12) {
00077         av_log(s->jpg.avctx, AV_LOG_ERROR,
00078                "MXM bitmask is not complete\n");
00079         return AVERROR(EINVAL);
00080     }
00081 
00082     if (s->bitmask_size != bitmask_size) {
00083         s->bitmask_size = 0;
00084         av_freep(&s->mxm_bitmask);
00085         s->mxm_bitmask = av_malloc(bitmask_size);
00086         if (!s->mxm_bitmask) {
00087             av_log(s->jpg.avctx, AV_LOG_ERROR,
00088                    "MXM bitmask memory allocation error\n");
00089             return AVERROR(ENOMEM);
00090         }
00091 
00092         av_freep(&s->completion_bitmask);
00093         s->completion_bitmask = av_mallocz(bitmask_size);
00094         if (!s->completion_bitmask) {
00095             av_log(s->jpg.avctx, AV_LOG_ERROR,
00096                    "Completion bitmask memory allocation error\n");
00097             return AVERROR(ENOMEM);
00098         }
00099 
00100         s->bitmask_size = bitmask_size;
00101     }
00102 
00103     memcpy(s->mxm_bitmask, buf_ptr + 12, bitmask_size);
00104     s->got_mxm_bitmask = 1;
00105 
00106     if (!s->has_complete_frame) {
00107         uint8_t completion_check = 0xFF;
00108         for (i = 0; i < bitmask_size; ++i) {
00109             s->completion_bitmask[i] |= s->mxm_bitmask[i];
00110             completion_check &= s->completion_bitmask[i];
00111         }
00112         s->has_complete_frame = !(completion_check ^ 0xFF);
00113     }
00114 
00115     return 0;
00116 }
00117 
00118 static int mxpeg_decode_com(MXpegDecodeContext *s,
00119                             const uint8_t *buf_ptr, int buf_size)
00120 {
00121     int len, ret = 0;
00122     if (buf_size < 2)
00123         return 0;
00124     len = AV_RB16(buf_ptr);
00125     if (len > 14 && len <= buf_size && !strncmp(buf_ptr + 2, "MXM", 3)) {
00126         ret = mxpeg_decode_mxm(s, buf_ptr + 2, len - 2);
00127     }
00128     skip_bits(&s->jpg.gb, 8*FFMIN(len,buf_size));
00129 
00130     return ret;
00131 }
00132 
00133 static int mxpeg_check_dimensions(MXpegDecodeContext *s, MJpegDecodeContext *jpg,
00134                                   AVFrame *reference_ptr)
00135 {
00136     if ((jpg->width + 0x0F)>>4 != s->mb_width ||
00137         (jpg->height + 0x0F)>>4 != s->mb_height) {
00138         av_log(jpg->avctx, AV_LOG_ERROR,
00139                "Picture dimensions stored in SOF and MXM mismatch\n");
00140         return AVERROR(EINVAL);
00141     }
00142 
00143     if (reference_ptr->data[0]) {
00144         int i;
00145         for (i = 0; i < MAX_COMPONENTS; ++i) {
00146             if ( (!reference_ptr->data[i] ^ !jpg->picture_ptr->data[i]) ||
00147                  reference_ptr->linesize[i] != jpg->picture_ptr->linesize[i]) {
00148                 av_log(jpg->avctx, AV_LOG_ERROR,
00149                        "Dimensions of current and reference picture mismatch\n");
00150                 return AVERROR(EINVAL);
00151             }
00152         }
00153     }
00154 
00155     return 0;
00156 }
00157 
00158 static int mxpeg_decode_frame(AVCodecContext *avctx,
00159                           void *data, int *data_size,
00160                           AVPacket *avpkt)
00161 {
00162     const uint8_t *buf = avpkt->data;
00163     int buf_size = avpkt->size;
00164     MXpegDecodeContext *s = avctx->priv_data;
00165     MJpegDecodeContext *jpg = &s->jpg;
00166     const uint8_t *buf_end, *buf_ptr;
00167     const uint8_t *unescaped_buf_ptr;
00168     int unescaped_buf_size;
00169     int start_code;
00170     AVFrame *picture = data;
00171     int ret;
00172 
00173     buf_ptr = buf;
00174     buf_end = buf + buf_size;
00175     jpg->got_picture = 0;
00176     s->got_mxm_bitmask = 0;
00177     while (buf_ptr < buf_end) {
00178         start_code = ff_mjpeg_find_marker(jpg, &buf_ptr, buf_end,
00179                                           &unescaped_buf_ptr, &unescaped_buf_size);
00180         if (start_code < 0)
00181             goto the_end;
00182         {
00183             init_get_bits(&jpg->gb, unescaped_buf_ptr, unescaped_buf_size*8);
00184 
00185             if (start_code >= APP0 && start_code <= APP15) {
00186                 mxpeg_decode_app(s, unescaped_buf_ptr, unescaped_buf_size);
00187             }
00188 
00189             switch (start_code) {
00190             case SOI:
00191                 if (jpg->got_picture) //emulating EOI
00192                     goto the_end;
00193                 break;
00194             case EOI:
00195                 goto the_end;
00196             case DQT:
00197                 ret = ff_mjpeg_decode_dqt(jpg);
00198                 if (ret < 0) {
00199                     av_log(avctx, AV_LOG_ERROR,
00200                            "quantization table decode error\n");
00201                     return ret;
00202                 }
00203                 break;
00204             case DHT:
00205                 ret = ff_mjpeg_decode_dht(jpg);
00206                 if (ret < 0) {
00207                     av_log(avctx, AV_LOG_ERROR,
00208                            "huffman table decode error\n");
00209                     return ret;
00210                 }
00211                 break;
00212             case COM:
00213                 ret = mxpeg_decode_com(s, unescaped_buf_ptr,
00214                                        unescaped_buf_size);
00215                 if (ret < 0)
00216                     return ret;
00217                 break;
00218             case SOF0:
00219                 s->got_sof_data = 0;
00220                 ret = ff_mjpeg_decode_sof(jpg);
00221                 if (ret < 0) {
00222                     av_log(avctx, AV_LOG_ERROR,
00223                            "SOF data decode error\n");
00224                     return ret;
00225                 }
00226                 if (jpg->interlaced) {
00227                     av_log(avctx, AV_LOG_ERROR,
00228                            "Interlaced mode not supported in MxPEG\n");
00229                     return AVERROR(EINVAL);
00230                 }
00231                 s->got_sof_data = 1;
00232                 break;
00233             case SOS:
00234                 if (!s->got_sof_data) {
00235                     av_log(avctx, AV_LOG_WARNING,
00236                            "Can not process SOS without SOF data, skipping\n");
00237                     break;
00238                 }
00239                 if (!jpg->got_picture) {
00240                     if (jpg->first_picture) {
00241                         av_log(avctx, AV_LOG_WARNING,
00242                                "First picture has no SOF, skipping\n");
00243                         break;
00244                     }
00245                     if (!s->got_mxm_bitmask){
00246                         av_log(avctx, AV_LOG_WARNING,
00247                                "Non-key frame has no MXM, skipping\n");
00248                         break;
00249                     }
00250                     /* use stored SOF data to allocate current picture */
00251                     if (jpg->picture_ptr->data[0])
00252                         avctx->release_buffer(avctx, jpg->picture_ptr);
00253                     if (avctx->get_buffer(avctx, jpg->picture_ptr) < 0) {
00254                         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00255                         return AVERROR(ENOMEM);
00256                     }
00257                     jpg->picture_ptr->pict_type = AV_PICTURE_TYPE_P;
00258                     jpg->picture_ptr->key_frame = 0;
00259                     jpg->got_picture = 1;
00260                 } else {
00261                     jpg->picture_ptr->pict_type = AV_PICTURE_TYPE_I;
00262                     jpg->picture_ptr->key_frame = 1;
00263                 }
00264 
00265                 if (s->got_mxm_bitmask) {
00266                     AVFrame *reference_ptr = &s->picture[s->picture_index ^ 1];
00267                     if (mxpeg_check_dimensions(s, jpg, reference_ptr) < 0)
00268                         break;
00269 
00270                     /* allocate dummy reference picture if needed */
00271                     if (!reference_ptr->data[0] &&
00272                         avctx->get_buffer(avctx, reference_ptr) < 0) {
00273                         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00274                         return AVERROR(ENOMEM);
00275                     }
00276 
00277                     ret = ff_mjpeg_decode_sos(jpg, s->mxm_bitmask, reference_ptr);
00278                     if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE))
00279                         return ret;
00280                 } else {
00281                     ret = ff_mjpeg_decode_sos(jpg, NULL, NULL);
00282                     if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE))
00283                         return ret;
00284                 }
00285 
00286                 break;
00287             }
00288 
00289             buf_ptr += (get_bits_count(&jpg->gb)+7) >> 3;
00290         }
00291 
00292     }
00293 
00294 the_end:
00295     if (jpg->got_picture) {
00296         *data_size = sizeof(AVFrame);
00297         *picture = *jpg->picture_ptr;
00298         s->picture_index ^= 1;
00299         jpg->picture_ptr = &s->picture[s->picture_index];
00300 
00301         if (!s->has_complete_frame) {
00302             if (!s->got_mxm_bitmask)
00303                 s->has_complete_frame = 1;
00304             else
00305                 *data_size = 0;
00306         }
00307     }
00308 
00309     return buf_ptr - buf;
00310 }
00311 
00312 static av_cold int mxpeg_decode_end(AVCodecContext *avctx)
00313 {
00314     MXpegDecodeContext *s = avctx->priv_data;
00315     MJpegDecodeContext *jpg = &s->jpg;
00316     int i;
00317 
00318     jpg->picture_ptr = NULL;
00319     ff_mjpeg_decode_end(avctx);
00320 
00321     for (i = 0; i < 2; ++i) {
00322         if (s->picture[i].data[0])
00323             avctx->release_buffer(avctx, &s->picture[i]);
00324     }
00325 
00326     av_freep(&s->mxm_bitmask);
00327     av_freep(&s->completion_bitmask);
00328 
00329     return 0;
00330 }
00331 
00332 AVCodec ff_mxpeg_decoder = {
00333     .name           = "mxpeg",
00334     .long_name      = NULL_IF_CONFIG_SMALL("Mobotix MxPEG video"),
00335     .type           = AVMEDIA_TYPE_VIDEO,
00336     .id             = CODEC_ID_MXPEG,
00337     .priv_data_size = sizeof(MXpegDecodeContext),
00338     .init           = mxpeg_decode_init,
00339     .close          = mxpeg_decode_end,
00340     .decode         = mxpeg_decode_frame,
00341     .capabilities   = CODEC_CAP_DR1,
00342     .max_lowres     = 3
00343 };
Generated on Fri Feb 1 2013 14:34:40 for FFmpeg by doxygen 1.7.1