LCOV - code coverage report
Current view: top level - libavformat - mxg.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 113 128 88.3 %
Date: 2017-12-10 21:22:29 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /*
       2             :  * MxPEG clip file demuxer
       3             :  * Copyright (c) 2010 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             : #include "libavutil/channel_layout.h"
      23             : #include "libavutil/internal.h"
      24             : #include "libavutil/intreadwrite.h"
      25             : #include "libavcodec/mjpeg.h"
      26             : #include "avformat.h"
      27             : #include "internal.h"
      28             : #include "avio.h"
      29             : 
      30             : #define DEFAULT_PACKET_SIZE 1024
      31             : #define OVERREAD_SIZE 3
      32             : 
      33             : typedef struct MXGContext {
      34             :     uint8_t *buffer;
      35             :     uint8_t *buffer_ptr;
      36             :     uint8_t *soi_ptr;
      37             :     unsigned int buffer_size;
      38             :     int64_t dts;
      39             :     unsigned int cache_size;
      40             : } MXGContext;
      41             : 
      42           1 : static int mxg_read_header(AVFormatContext *s)
      43             : {
      44             :     AVStream *video_st, *audio_st;
      45           1 :     MXGContext *mxg = s->priv_data;
      46             : 
      47             :     /* video parameters will be extracted from the compressed bitstream */
      48           1 :     video_st = avformat_new_stream(s, NULL);
      49           1 :     if (!video_st)
      50           0 :         return AVERROR(ENOMEM);
      51           1 :     video_st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
      52           1 :     video_st->codecpar->codec_id = AV_CODEC_ID_MXPEG;
      53           1 :     avpriv_set_pts_info(video_st, 64, 1, 1000000);
      54             : 
      55           1 :     audio_st = avformat_new_stream(s, NULL);
      56           1 :     if (!audio_st)
      57           0 :         return AVERROR(ENOMEM);
      58           1 :     audio_st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
      59           1 :     audio_st->codecpar->codec_id = AV_CODEC_ID_PCM_ALAW;
      60           1 :     audio_st->codecpar->channels = 1;
      61           1 :     audio_st->codecpar->channel_layout = AV_CH_LAYOUT_MONO;
      62           1 :     audio_st->codecpar->sample_rate = 8000;
      63           1 :     audio_st->codecpar->bits_per_coded_sample = 8;
      64           1 :     audio_st->codecpar->block_align = 1;
      65           1 :     avpriv_set_pts_info(audio_st, 64, 1, 1000000);
      66             : 
      67           1 :     mxg->soi_ptr = mxg->buffer_ptr = mxg->buffer = 0;
      68           1 :     mxg->buffer_size = 0;
      69           1 :     mxg->dts = AV_NOPTS_VALUE;
      70           1 :     mxg->cache_size = 0;
      71             : 
      72           1 :     return 0;
      73             : }
      74             : 
      75        8365 : static uint8_t* mxg_find_startmarker(uint8_t *p, uint8_t *end)
      76             : {
      77      139149 :     for (; p < end - 3; p += 4) {
      78      138625 :         uint32_t x = AV_RN32(p);
      79             : 
      80      138625 :         if (x & (~(x+0x01010101)) & 0x80808080) {
      81        7841 :             if (p[0] == 0xff) {
      82        1627 :                 return p;
      83        6214 :             } else if (p[1] == 0xff) {
      84        1718 :                 return p+1;
      85        4496 :             } else if (p[2] == 0xff) {
      86        2815 :                 return p+2;
      87        1681 :             } else if (p[3] == 0xff) {
      88        1681 :                 return p+3;
      89             :             }
      90             :         }
      91             :     }
      92             : 
      93        1274 :     for (; p < end; ++p) {
      94         763 :         if (*p == 0xff) return p;
      95             :     }
      96             : 
      97         511 :     return end;
      98             : }
      99             : 
     100         590 : static int mxg_update_cache(AVFormatContext *s, unsigned int cache_size)
     101             : {
     102         590 :     MXGContext *mxg = s->priv_data;
     103         590 :     unsigned int current_pos = mxg->buffer_ptr - mxg->buffer;
     104             :     unsigned int soi_pos;
     105             :     uint8_t *buffer;
     106             :     int ret;
     107             : 
     108             :     /* reallocate internal buffer */
     109         590 :     if (current_pos > current_pos + cache_size)
     110           0 :         return AVERROR(ENOMEM);
     111         590 :     soi_pos = mxg->soi_ptr - mxg->buffer;
     112         590 :     buffer = av_fast_realloc(mxg->buffer, &mxg->buffer_size,
     113         590 :                              current_pos + cache_size +
     114             :                              AV_INPUT_BUFFER_PADDING_SIZE);
     115         590 :     if (!buffer)
     116           0 :         return AVERROR(ENOMEM);
     117         590 :     mxg->buffer = buffer;
     118         590 :     mxg->buffer_ptr = mxg->buffer + current_pos;
     119         590 :     if (mxg->soi_ptr) mxg->soi_ptr = mxg->buffer + soi_pos;
     120             : 
     121             :     /* get data */
     122         590 :     ret = avio_read(s->pb, mxg->buffer_ptr + mxg->cache_size,
     123         590 :                      cache_size - mxg->cache_size);
     124         590 :     if (ret < 0)
     125           0 :         return ret;
     126             : 
     127         590 :     mxg->cache_size += ret;
     128             : 
     129         590 :     return ret;
     130             : }
     131             : 
     132          32 : static int mxg_read_packet(AVFormatContext *s, AVPacket *pkt)
     133             : {
     134             :     int ret;
     135             :     unsigned int size;
     136             :     uint8_t *startmarker_ptr, *end, *search_end, marker;
     137          32 :     MXGContext *mxg = s->priv_data;
     138             : 
     139        8398 :     while (!avio_feof(s->pb) && !s->pb->error){
     140        8365 :         if (mxg->cache_size <= OVERREAD_SIZE) {
     141             :             /* update internal buffer */
     142         560 :             ret = mxg_update_cache(s, DEFAULT_PACKET_SIZE + OVERREAD_SIZE);
     143         560 :             if (ret < 0)
     144           0 :                 return ret;
     145             :         }
     146        8365 :         end = mxg->buffer_ptr + mxg->cache_size;
     147             : 
     148             :         /* find start marker - 0xff */
     149        8365 :         if (mxg->cache_size > OVERREAD_SIZE) {
     150        8365 :             search_end = end - OVERREAD_SIZE;
     151        8365 :             startmarker_ptr = mxg_find_startmarker(mxg->buffer_ptr, search_end);
     152             :         } else {
     153           0 :             search_end = end;
     154           0 :             startmarker_ptr = mxg_find_startmarker(mxg->buffer_ptr, search_end);
     155           0 :             if (startmarker_ptr >= search_end - 1 ||
     156           0 :                 *(startmarker_ptr + 1) != EOI) break;
     157             :         }
     158             : 
     159        8365 :         if (startmarker_ptr != search_end) { /* start marker found */
     160        7854 :             marker = *(startmarker_ptr + 1);
     161        7854 :             mxg->buffer_ptr = startmarker_ptr + 2;
     162        7854 :             mxg->cache_size = end - mxg->buffer_ptr;
     163             : 
     164        7854 :             if (marker == SOI) {
     165          31 :                 mxg->soi_ptr = startmarker_ptr;
     166        7823 :             } else if (marker == EOI) {
     167          30 :                 if (!mxg->soi_ptr) {
     168           0 :                     av_log(s, AV_LOG_WARNING, "Found EOI before SOI, skipping\n");
     169           0 :                     continue;
     170             :                 }
     171             : 
     172          30 :                 pkt->pts = pkt->dts = mxg->dts;
     173          30 :                 pkt->stream_index = 0;
     174          30 :                 pkt->buf  = NULL;
     175          30 :                 pkt->size = mxg->buffer_ptr - mxg->soi_ptr;
     176          30 :                 pkt->data = mxg->soi_ptr;
     177             : 
     178          30 :                 if (mxg->soi_ptr - mxg->buffer > mxg->cache_size) {
     179          14 :                     if (mxg->cache_size > 0) {
     180          14 :                         memmove(mxg->buffer, mxg->buffer_ptr, mxg->cache_size);
     181             :                     }
     182             : 
     183          14 :                     mxg->buffer_ptr = mxg->buffer;
     184             :                 }
     185          30 :                 mxg->soi_ptr = 0;
     186             : 
     187          30 :                 return pkt->size;
     188        7793 :             } else if ( (SOF0 <= marker && marker <= SOF15) ||
     189         128 :                         (SOS  <= marker && marker <= COM) ) {
     190             :                 /* all other markers that start marker segment also contain
     191             :                    length value (see specification for JPEG Annex B.1) */
     192         133 :                 size = AV_RB16(mxg->buffer_ptr);
     193         133 :                 if (size < 2)
     194           0 :                     return AVERROR(EINVAL);
     195             : 
     196         133 :                 if (mxg->cache_size < size) {
     197          30 :                     ret = mxg_update_cache(s, size);
     198          30 :                     if (ret < 0)
     199           0 :                         return ret;
     200          30 :                     startmarker_ptr = mxg->buffer_ptr - 2;
     201          30 :                     mxg->cache_size = 0;
     202             :                 } else {
     203         103 :                     mxg->cache_size -= size;
     204             :                 }
     205             : 
     206         133 :                 mxg->buffer_ptr += size;
     207             : 
     208         133 :                 if (marker == APP13 && size >= 16) { /* audio data */
     209             :                     /* time (GMT) of first sample in usec since 1970, little-endian */
     210           1 :                     pkt->pts = pkt->dts = AV_RL64(startmarker_ptr + 8);
     211           1 :                     pkt->stream_index = 1;
     212           1 :                     pkt->buf  = NULL;
     213           1 :                     pkt->size = size - 14;
     214           1 :                     pkt->data = startmarker_ptr + 16;
     215             : 
     216           1 :                     if (startmarker_ptr - mxg->buffer > mxg->cache_size) {
     217           1 :                         if (mxg->cache_size > 0) {
     218           0 :                             memcpy(mxg->buffer, mxg->buffer_ptr, mxg->cache_size);
     219             :                         }
     220           1 :                         mxg->buffer_ptr = mxg->buffer;
     221             :                     }
     222             : 
     223           1 :                     return pkt->size;
     224         195 :                 } else if (marker == COM && size >= 18 &&
     225          63 :                            !strncmp(startmarker_ptr + 4, "MXF", 3)) {
     226             :                     /* time (GMT) of video frame in usec since 1970, little-endian */
     227          31 :                     mxg->dts = AV_RL64(startmarker_ptr + 12);
     228             :                 }
     229             :             }
     230             :         } else {
     231             :             /* start marker not found */
     232         511 :             mxg->buffer_ptr = search_end;
     233         511 :             mxg->cache_size = OVERREAD_SIZE;
     234             :         }
     235             :     }
     236             : 
     237           1 :     return AVERROR_EOF;
     238             : }
     239             : 
     240           1 : static int mxg_close(struct AVFormatContext *s)
     241             : {
     242           1 :     MXGContext *mxg = s->priv_data;
     243           1 :     av_freep(&mxg->buffer);
     244           1 :     return 0;
     245             : }
     246             : 
     247             : AVInputFormat ff_mxg_demuxer = {
     248             :     .name           = "mxg",
     249             :     .long_name      = NULL_IF_CONFIG_SMALL("MxPEG clip"),
     250             :     .priv_data_size = sizeof(MXGContext),
     251             :     .read_header    = mxg_read_header,
     252             :     .read_packet    = mxg_read_packet,
     253             :     .read_close     = mxg_close,
     254             :     .extensions     = "mxg",
     255             : };

Generated by: LCOV version 1.13