"Fossies" - the Fresh Open Source Software Archive

Member "ffmpeg-4.0.1/libavformat/4xm.c" (13 Apr 2018, 13185 Bytes) of package /linux/misc/ffmpeg-4.0.1.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "4xm.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * 4X Technologies .4xm File Demuxer (no muxer)
    3  * Copyright (c) 2003  The FFmpeg project
    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  * @file
   24  * 4X Technologies file demuxer
   25  * by Mike Melanson (melanson@pcisys.net)
   26  * for more information on the .4xm file format, visit:
   27  *   http://www.pcisys.net/~melanson/codecs/
   28  */
   29 
   30 #include "libavutil/intreadwrite.h"
   31 #include "libavutil/intfloat.h"
   32 #include "libavcodec/internal.h"
   33 #include "avformat.h"
   34 #include "internal.h"
   35 
   36 #define     RIFF_TAG MKTAG('R', 'I', 'F', 'F')
   37 #define  FOURXMV_TAG MKTAG('4', 'X', 'M', 'V')
   38 #define     LIST_TAG MKTAG('L', 'I', 'S', 'T')
   39 #define     HEAD_TAG MKTAG('H', 'E', 'A', 'D')
   40 #define     TRK__TAG MKTAG('T', 'R', 'K', '_')
   41 #define     MOVI_TAG MKTAG('M', 'O', 'V', 'I')
   42 #define     VTRK_TAG MKTAG('V', 'T', 'R', 'K')
   43 #define     STRK_TAG MKTAG('S', 'T', 'R', 'K')
   44 #define     std__TAG MKTAG('s', 't', 'd', '_')
   45 #define     name_TAG MKTAG('n', 'a', 'm', 'e')
   46 #define     vtrk_TAG MKTAG('v', 't', 'r', 'k')
   47 #define     strk_TAG MKTAG('s', 't', 'r', 'k')
   48 #define     ifrm_TAG MKTAG('i', 'f', 'r', 'm')
   49 #define     pfrm_TAG MKTAG('p', 'f', 'r', 'm')
   50 #define     cfrm_TAG MKTAG('c', 'f', 'r', 'm')
   51 #define     ifr2_TAG MKTAG('i', 'f', 'r', '2')
   52 #define     pfr2_TAG MKTAG('p', 'f', 'r', '2')
   53 #define     cfr2_TAG MKTAG('c', 'f', 'r', '2')
   54 #define     snd__TAG MKTAG('s', 'n', 'd', '_')
   55 
   56 #define vtrk_SIZE 0x44
   57 #define strk_SIZE 0x28
   58 
   59 #define GET_LIST_HEADER() \
   60     fourcc_tag = avio_rl32(pb); \
   61     size       = avio_rl32(pb); \
   62     if (fourcc_tag != LIST_TAG) \
   63         return AVERROR_INVALIDDATA; \
   64     fourcc_tag = avio_rl32(pb);
   65 
   66 typedef struct AudioTrack {
   67     int sample_rate;
   68     int bits;
   69     int channels;
   70     int stream_index;
   71     int adpcm;
   72     int64_t audio_pts;
   73 } AudioTrack;
   74 
   75 typedef struct FourxmDemuxContext {
   76     int video_stream_index;
   77     int track_count;
   78     AudioTrack *tracks;
   79 
   80     int64_t video_pts;
   81     AVRational fps;
   82 } FourxmDemuxContext;
   83 
   84 static int fourxm_probe(AVProbeData *p)
   85 {
   86     if ((AV_RL32(&p->buf[0]) != RIFF_TAG) ||
   87         (AV_RL32(&p->buf[8]) != FOURXMV_TAG))
   88         return 0;
   89 
   90     return AVPROBE_SCORE_MAX;
   91 }
   92 
   93 static int parse_vtrk(AVFormatContext *s,
   94                       FourxmDemuxContext *fourxm, uint8_t *buf, int size,
   95                       int left)
   96 {
   97     AVStream *st;
   98     /* check that there is enough data */
   99     if (size != vtrk_SIZE || left < size + 8) {
  100         return AVERROR_INVALIDDATA;
  101     }
  102 
  103     /* allocate a new AVStream */
  104     st = avformat_new_stream(s, NULL);
  105     if (!st)
  106         return AVERROR(ENOMEM);
  107 
  108     avpriv_set_pts_info(st, 60, fourxm->fps.den, fourxm->fps.num);
  109 
  110     fourxm->video_stream_index = st->index;
  111 
  112     st->codecpar->codec_type     = AVMEDIA_TYPE_VIDEO;
  113     st->codecpar->codec_id       = AV_CODEC_ID_4XM;
  114 
  115     st->codecpar->extradata      = av_mallocz(4 + AV_INPUT_BUFFER_PADDING_SIZE);
  116     if (!st->codecpar->extradata)
  117         return AVERROR(ENOMEM);
  118     st->codecpar->extradata_size = 4;
  119     AV_WL32(st->codecpar->extradata, AV_RL32(buf + 16));
  120     st->codecpar->width  = AV_RL32(buf + 36);
  121     st->codecpar->height = AV_RL32(buf + 40);
  122 
  123     return 0;
  124 }
  125 
  126 
  127 static int parse_strk(AVFormatContext *s,
  128                       FourxmDemuxContext *fourxm, uint8_t *buf, int size,
  129                       int left)
  130 {
  131     AVStream *st;
  132     int track;
  133     /* check that there is enough data */
  134     if (size != strk_SIZE || left < size + 8)
  135         return AVERROR_INVALIDDATA;
  136 
  137     track = AV_RL32(buf + 8);
  138     if ((unsigned)track >= UINT_MAX / sizeof(AudioTrack) - 1) {
  139         av_log(s, AV_LOG_ERROR, "current_track too large\n");
  140         return AVERROR_INVALIDDATA;
  141     }
  142 
  143     if (track + 1 > fourxm->track_count) {
  144         if (av_reallocp_array(&fourxm->tracks, track + 1, sizeof(AudioTrack)))
  145             return AVERROR(ENOMEM);
  146         memset(&fourxm->tracks[fourxm->track_count], 0,
  147                sizeof(AudioTrack) * (track + 1 - fourxm->track_count));
  148         fourxm->track_count = track + 1;
  149     }
  150     fourxm->tracks[track].adpcm       = AV_RL32(buf + 12);
  151     fourxm->tracks[track].channels    = AV_RL32(buf + 36);
  152     fourxm->tracks[track].sample_rate = AV_RL32(buf + 40);
  153     fourxm->tracks[track].bits        = AV_RL32(buf + 44);
  154     fourxm->tracks[track].audio_pts   = 0;
  155 
  156     if (fourxm->tracks[track].channels    <= 0 ||
  157         fourxm->tracks[track].channels     > FF_SANE_NB_CHANNELS ||
  158         fourxm->tracks[track].sample_rate <= 0 ||
  159         fourxm->tracks[track].bits        <= 0 ||
  160         fourxm->tracks[track].bits         > INT_MAX / FF_SANE_NB_CHANNELS) {
  161         av_log(s, AV_LOG_ERROR, "audio header invalid\n");
  162         return AVERROR_INVALIDDATA;
  163     }
  164     if (!fourxm->tracks[track].adpcm && fourxm->tracks[track].bits<8) {
  165         av_log(s, AV_LOG_ERROR, "bits unspecified for non ADPCM\n");
  166         return AVERROR_INVALIDDATA;
  167     }
  168 
  169     if (fourxm->tracks[track].sample_rate > INT64_MAX / fourxm->tracks[track].bits / fourxm->tracks[track].channels) {
  170         av_log(s, AV_LOG_ERROR, "Overflow during bit rate calculation %d * %d * %d\n",
  171                fourxm->tracks[track].sample_rate, fourxm->tracks[track].bits, fourxm->tracks[track].channels);
  172         return AVERROR_INVALIDDATA;
  173     }
  174 
  175     /* allocate a new AVStream */
  176     st = avformat_new_stream(s, NULL);
  177     if (!st)
  178         return AVERROR(ENOMEM);
  179 
  180     st->id = track;
  181     avpriv_set_pts_info(st, 60, 1, fourxm->tracks[track].sample_rate);
  182 
  183     fourxm->tracks[track].stream_index = st->index;
  184 
  185     st->codecpar->codec_type            = AVMEDIA_TYPE_AUDIO;
  186     st->codecpar->codec_tag             = 0;
  187     st->codecpar->channels              = fourxm->tracks[track].channels;
  188     st->codecpar->sample_rate           = fourxm->tracks[track].sample_rate;
  189     st->codecpar->bits_per_coded_sample = fourxm->tracks[track].bits;
  190     st->codecpar->bit_rate              = (int64_t)st->codecpar->channels *
  191                                           st->codecpar->sample_rate *
  192                                           st->codecpar->bits_per_coded_sample;
  193     st->codecpar->block_align           = st->codecpar->channels *
  194                                           st->codecpar->bits_per_coded_sample;
  195 
  196     if (fourxm->tracks[track].adpcm){
  197         st->codecpar->codec_id = AV_CODEC_ID_ADPCM_4XM;
  198     } else if (st->codecpar->bits_per_coded_sample == 8) {
  199         st->codecpar->codec_id = AV_CODEC_ID_PCM_U8;
  200     } else
  201         st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE;
  202 
  203     return 0;
  204 }
  205 
  206 static int fourxm_read_header(AVFormatContext *s)
  207 {
  208     AVIOContext *pb = s->pb;
  209     unsigned int fourcc_tag;
  210     unsigned int size;
  211     int header_size;
  212     FourxmDemuxContext *fourxm = s->priv_data;
  213     unsigned char *header;
  214     int i, ret;
  215 
  216     fourxm->track_count = 0;
  217     fourxm->tracks      = NULL;
  218     fourxm->fps         = (AVRational){1,1};
  219 
  220     /* skip the first 3 32-bit numbers */
  221     avio_skip(pb, 12);
  222 
  223     /* check for LIST-HEAD */
  224     GET_LIST_HEADER();
  225     header_size = size - 4;
  226     if (fourcc_tag != HEAD_TAG || header_size < 0)
  227         return AVERROR_INVALIDDATA;
  228 
  229     /* allocate space for the header and load the whole thing */
  230     header = av_malloc(header_size);
  231     if (!header)
  232         return AVERROR(ENOMEM);
  233     if (avio_read(pb, header, header_size) != header_size) {
  234         av_free(header);
  235         return AVERROR(EIO);
  236     }
  237 
  238     /* take the lazy approach and search for any and all vtrk and strk chunks */
  239     for (i = 0; i < header_size - 8; i++) {
  240         fourcc_tag = AV_RL32(&header[i]);
  241         size       = AV_RL32(&header[i + 4]);
  242         if (size > header_size - i - 8 && (fourcc_tag == vtrk_TAG || fourcc_tag == strk_TAG)) {
  243             av_log(s, AV_LOG_ERROR, "chunk larger than array %d>%d\n", size, header_size - i - 8);
  244             return AVERROR_INVALIDDATA;
  245         }
  246 
  247         if (fourcc_tag == std__TAG) {
  248             if (header_size - i < 16) {
  249                 av_log(s, AV_LOG_ERROR, "std TAG truncated\n");
  250                 ret = AVERROR_INVALIDDATA;
  251                 goto fail;
  252             }
  253             fourxm->fps = av_d2q(av_int2float(AV_RL32(&header[i + 12])), 10000);
  254         } else if (fourcc_tag == vtrk_TAG) {
  255             if ((ret = parse_vtrk(s, fourxm, header + i, size,
  256                                   header_size - i)) < 0)
  257                 goto fail;
  258 
  259             i += 8 + size;
  260         } else if (fourcc_tag == strk_TAG) {
  261             if ((ret = parse_strk(s, fourxm, header + i, size,
  262                                   header_size - i)) < 0)
  263                 goto fail;
  264 
  265             i += 8 + size;
  266         }
  267     }
  268 
  269     /* skip over the LIST-MOVI chunk (which is where the stream should be */
  270     GET_LIST_HEADER();
  271     if (fourcc_tag != MOVI_TAG) {
  272         ret = AVERROR_INVALIDDATA;
  273         goto fail;
  274     }
  275 
  276     av_free(header);
  277     /* initialize context members */
  278     fourxm->video_pts = -1;  /* first frame will push to 0 */
  279 
  280     return 0;
  281 fail:
  282     av_freep(&fourxm->tracks);
  283     av_free(header);
  284     return ret;
  285 }
  286 
  287 static int fourxm_read_packet(AVFormatContext *s,
  288                               AVPacket *pkt)
  289 {
  290     FourxmDemuxContext *fourxm = s->priv_data;
  291     AVIOContext *pb            = s->pb;
  292     unsigned int fourcc_tag;
  293     unsigned int size;
  294     int ret = 0;
  295     unsigned int track_number;
  296     int packet_read = 0;
  297     unsigned char header[8];
  298     int audio_frame_count;
  299 
  300     while (!packet_read) {
  301         if ((ret = avio_read(s->pb, header, 8)) < 0)
  302             return ret;
  303         fourcc_tag = AV_RL32(&header[0]);
  304         size       = AV_RL32(&header[4]);
  305         if (avio_feof(pb))
  306             return AVERROR(EIO);
  307         switch (fourcc_tag) {
  308         case LIST_TAG:
  309             /* this is a good time to bump the video pts */
  310             fourxm->video_pts++;
  311 
  312             /* skip the LIST-* tag and move on to the next fourcc */
  313             avio_rl32(pb);
  314             break;
  315 
  316         case ifrm_TAG:
  317         case pfrm_TAG:
  318         case cfrm_TAG:
  319         case ifr2_TAG:
  320         case pfr2_TAG:
  321         case cfr2_TAG:
  322             /* allocate 8 more bytes than 'size' to account for fourcc
  323              * and size */
  324             if (size + 8 < size || av_new_packet(pkt, size + 8))
  325                 return AVERROR(EIO);
  326             pkt->stream_index = fourxm->video_stream_index;
  327             pkt->pts          = fourxm->video_pts;
  328             pkt->pos          = avio_tell(s->pb);
  329             memcpy(pkt->data, header, 8);
  330             ret = avio_read(s->pb, &pkt->data[8], size);
  331 
  332             if (ret < 0) {
  333                 av_packet_unref(pkt);
  334             } else {
  335                 packet_read = 1;
  336                 av_shrink_packet(pkt, ret + 8);
  337             }
  338             break;
  339 
  340         case snd__TAG:
  341             track_number = avio_rl32(pb);
  342             avio_skip(pb, 4);
  343             size -= 8;
  344 
  345             if (track_number < fourxm->track_count &&
  346                 fourxm->tracks[track_number].channels > 0) {
  347                 ret = av_get_packet(s->pb, pkt, size);
  348                 if (ret < 0)
  349                     return AVERROR(EIO);
  350                 pkt->stream_index =
  351                     fourxm->tracks[track_number].stream_index;
  352                 pkt->pts    = fourxm->tracks[track_number].audio_pts;
  353                 packet_read = 1;
  354 
  355                 /* pts accounting */
  356                 audio_frame_count = size;
  357                 if (fourxm->tracks[track_number].adpcm)
  358                     audio_frame_count -= 2 * (fourxm->tracks[track_number].channels);
  359                 audio_frame_count /= fourxm->tracks[track_number].channels;
  360                 if (fourxm->tracks[track_number].adpcm) {
  361                     audio_frame_count *= 2;
  362                 } else
  363                     audio_frame_count /=
  364                         (fourxm->tracks[track_number].bits / 8);
  365                 fourxm->tracks[track_number].audio_pts += audio_frame_count;
  366             } else {
  367                 avio_skip(pb, size);
  368             }
  369             break;
  370 
  371         default:
  372             avio_skip(pb, size);
  373             break;
  374         }
  375     }
  376     return ret;
  377 }
  378 
  379 static int fourxm_read_close(AVFormatContext *s)
  380 {
  381     FourxmDemuxContext *fourxm = s->priv_data;
  382 
  383     av_freep(&fourxm->tracks);
  384 
  385     return 0;
  386 }
  387 
  388 AVInputFormat ff_fourxm_demuxer = {
  389     .name           = "4xm",
  390     .long_name      = NULL_IF_CONFIG_SMALL("4X Technologies"),
  391     .priv_data_size = sizeof(FourxmDemuxContext),
  392     .read_probe     = fourxm_probe,
  393     .read_header    = fourxm_read_header,
  394     .read_packet    = fourxm_read_packet,
  395     .read_close     = fourxm_read_close,
  396 };