LCOV - code coverage report
Current view: top level - libavcodec - mxpegdec.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 131 174 75.3 %
Date: 2017-12-10 21:22:29 Functions: 7 7 100.0 %

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

Generated by: LCOV version 1.13