Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * SoX native format demuxer
  3.  * Copyright (c) 2009 Daniel Verkamp <daniel@drv.nu>
  4.  *
  5.  * Based on libSoX sox-fmt.c
  6.  * Copyright (c) 2008 robs@users.sourceforge.net
  7.  *
  8.  * This file is part of FFmpeg.
  9.  *
  10.  * FFmpeg is free software; you can redistribute it and/or
  11.  * modify it under the terms of the GNU Lesser General Public
  12.  * License as published by the Free Software Foundation; either
  13.  * version 2.1 of the License, or (at your option) any later version.
  14.  *
  15.  * FFmpeg is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18.  * Lesser General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU Lesser General Public
  21.  * License along with FFmpeg; if not, write to the Free Software
  22.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  23.  */
  24.  
  25. /**
  26.  * @file
  27.  * SoX native format demuxer
  28.  * @author Daniel Verkamp
  29.  * @see http://wiki.multimedia.cx/index.php?title=SoX_native_intermediate_format
  30.  */
  31.  
  32. #include "libavutil/intreadwrite.h"
  33. #include "libavutil/intfloat.h"
  34. #include "libavutil/dict.h"
  35. #include "avformat.h"
  36. #include "internal.h"
  37. #include "pcm.h"
  38. #include "sox.h"
  39.  
  40. static int sox_probe(AVProbeData *p)
  41. {
  42.     if (AV_RL32(p->buf) == SOX_TAG || AV_RB32(p->buf) == SOX_TAG)
  43.         return AVPROBE_SCORE_MAX;
  44.     return 0;
  45. }
  46.  
  47. static int sox_read_header(AVFormatContext *s)
  48. {
  49.     AVIOContext *pb = s->pb;
  50.     unsigned header_size, comment_size;
  51.     double sample_rate, sample_rate_frac;
  52.     AVStream *st;
  53.  
  54.     st = avformat_new_stream(s, NULL);
  55.     if (!st)
  56.         return AVERROR(ENOMEM);
  57.  
  58.     st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
  59.  
  60.     if (avio_rl32(pb) == SOX_TAG) {
  61.         st->codec->codec_id = AV_CODEC_ID_PCM_S32LE;
  62.         header_size         = avio_rl32(pb);
  63.         avio_skip(pb, 8); /* sample count */
  64.         sample_rate         = av_int2double(avio_rl64(pb));
  65.         st->codec->channels = avio_rl32(pb);
  66.         comment_size        = avio_rl32(pb);
  67.     } else {
  68.         st->codec->codec_id = AV_CODEC_ID_PCM_S32BE;
  69.         header_size         = avio_rb32(pb);
  70.         avio_skip(pb, 8); /* sample count */
  71.         sample_rate         = av_int2double(avio_rb64(pb));
  72.         st->codec->channels = avio_rb32(pb);
  73.         comment_size        = avio_rb32(pb);
  74.     }
  75.  
  76.     if (comment_size > 0xFFFFFFFFU - SOX_FIXED_HDR - 4U) {
  77.         av_log(s, AV_LOG_ERROR, "invalid comment size (%u)\n", comment_size);
  78.         return AVERROR_INVALIDDATA;
  79.     }
  80.  
  81.     if (sample_rate <= 0 || sample_rate > INT_MAX) {
  82.         av_log(s, AV_LOG_ERROR, "invalid sample rate (%f)\n", sample_rate);
  83.         return AVERROR_INVALIDDATA;
  84.     }
  85.  
  86.     sample_rate_frac = sample_rate - floor(sample_rate);
  87.     if (sample_rate_frac)
  88.         av_log(s, AV_LOG_WARNING,
  89.                "truncating fractional part of sample rate (%f)\n",
  90.                sample_rate_frac);
  91.  
  92.     if ((header_size + 4) & 7 || header_size < SOX_FIXED_HDR + comment_size
  93.         || st->codec->channels > 65535) /* Reserve top 16 bits */ {
  94.         av_log(s, AV_LOG_ERROR, "invalid header\n");
  95.         return AVERROR_INVALIDDATA;
  96.     }
  97.  
  98.     if (comment_size && comment_size < UINT_MAX) {
  99.         char *comment = av_malloc(comment_size+1);
  100.         if(!comment)
  101.             return AVERROR(ENOMEM);
  102.         if (avio_read(pb, comment, comment_size) != comment_size) {
  103.             av_freep(&comment);
  104.             return AVERROR(EIO);
  105.         }
  106.         comment[comment_size] = 0;
  107.  
  108.         av_dict_set(&s->metadata, "comment", comment,
  109.                                AV_DICT_DONT_STRDUP_VAL);
  110.     }
  111.  
  112.     avio_skip(pb, header_size - SOX_FIXED_HDR - comment_size);
  113.  
  114.     st->codec->sample_rate           = sample_rate;
  115.     st->codec->bits_per_coded_sample = 32;
  116.     st->codec->bit_rate              = st->codec->sample_rate *
  117.                                        st->codec->bits_per_coded_sample *
  118.                                        st->codec->channels;
  119.     st->codec->block_align           = st->codec->bits_per_coded_sample *
  120.                                        st->codec->channels / 8;
  121.  
  122.     avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
  123.  
  124.     return 0;
  125. }
  126.  
  127. AVInputFormat ff_sox_demuxer = {
  128.     .name           = "sox",
  129.     .long_name      = NULL_IF_CONFIG_SMALL("SoX native"),
  130.     .read_probe     = sox_probe,
  131.     .read_header    = sox_read_header,
  132.     .read_packet    = ff_pcm_read_packet,
  133.     .read_seek      = ff_pcm_read_seek,
  134. };
  135.