Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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