]> git.sesse.net Git - ffmpeg/blob - libavformat/soxdec.c
Merge remote-tracking branch 'qatar/master'
[ffmpeg] / libavformat / soxdec.c
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  * SoX native format demuxer
27  * @file
28  * @author Daniel Verkamp
29  * @sa http://wiki.multimedia.cx/index.php?title=SoX_native_intermediate_format
30  */
31
32 #include "libavutil/intreadwrite.h"
33 #include "libavutil/dict.h"
34 #include "avformat.h"
35 #include "pcm.h"
36 #include "sox.h"
37
38 static int sox_probe(AVProbeData *p)
39 {
40     if (AV_RL32(p->buf) == SOX_TAG || AV_RB32(p->buf) == SOX_TAG)
41         return AVPROBE_SCORE_MAX;
42     return 0;
43 }
44
45 static int sox_read_header(AVFormatContext *s,
46                            AVFormatParameters *ap)
47 {
48     AVIOContext *pb = s->pb;
49     unsigned header_size, comment_size;
50     double sample_rate, sample_rate_frac;
51     AVStream *st;
52
53     st = av_new_stream(s, 0);
54     if (!st)
55         return AVERROR(ENOMEM);
56
57     st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
58
59     if (avio_rl32(pb) == SOX_TAG) {
60         st->codec->codec_id = CODEC_ID_PCM_S32LE;
61         header_size         = avio_rl32(pb);
62         avio_skip(pb, 8); /* sample count */
63         sample_rate         = av_int2dbl(avio_rl64(pb));
64         st->codec->channels = avio_rl32(pb);
65         comment_size        = avio_rl32(pb);
66     } else {
67         st->codec->codec_id = CODEC_ID_PCM_S32BE;
68         header_size         = avio_rb32(pb);
69         avio_skip(pb, 8); /* sample count */
70         sample_rate         = av_int2dbl(avio_rb64(pb));
71         st->codec->channels = avio_rb32(pb);
72         comment_size        = avio_rb32(pb);
73     }
74
75     if (comment_size > 0xFFFFFFFFU - SOX_FIXED_HDR - 4U) {
76         av_log(s, AV_LOG_ERROR, "invalid comment size (%u)\n", comment_size);
77         return -1;
78     }
79
80     if (sample_rate <= 0 || sample_rate > INT_MAX) {
81         av_log(s, AV_LOG_ERROR, "invalid sample rate (%f)\n", sample_rate);
82         return -1;
83     }
84
85     sample_rate_frac = sample_rate - floor(sample_rate);
86     if (sample_rate_frac)
87         av_log(s, AV_LOG_WARNING,
88                "truncating fractional part of sample rate (%f)\n",
89                sample_rate_frac);
90
91     if ((header_size + 4) & 7 || header_size < SOX_FIXED_HDR + comment_size
92         || st->codec->channels > 65535) /* Reserve top 16 bits */ {
93         av_log(s, AV_LOG_ERROR, "invalid header\n");
94         return -1;
95     }
96
97     if (comment_size && comment_size < UINT_MAX) {
98         char *comment = av_malloc(comment_size+1);
99         if (avio_read(pb, comment, comment_size) != comment_size) {
100             av_freep(&comment);
101             return AVERROR(EIO);
102         }
103         comment[comment_size] = 0;
104
105         av_dict_set(&s->metadata, "comment", comment,
106                                AV_DICT_DONT_STRDUP_VAL);
107     }
108
109     avio_skip(pb, header_size - SOX_FIXED_HDR - comment_size);
110
111     st->codec->sample_rate           = sample_rate;
112     st->codec->bits_per_coded_sample = 32;
113     st->codec->bit_rate              = st->codec->sample_rate *
114                                        st->codec->bits_per_coded_sample *
115                                        st->codec->channels;
116     st->codec->block_align           = st->codec->bits_per_coded_sample *
117                                        st->codec->channels / 8;
118
119     av_set_pts_info(st, 64, 1, st->codec->sample_rate);
120
121     return 0;
122 }
123
124 #define SOX_SAMPLES 1024
125
126 static int sox_read_packet(AVFormatContext *s,
127                            AVPacket *pkt)
128 {
129     int ret, size;
130
131     if (url_feof(s->pb))
132         return AVERROR_EOF;
133
134     size = SOX_SAMPLES*s->streams[0]->codec->block_align;
135     ret = av_get_packet(s->pb, pkt, size);
136     if (ret < 0)
137         return AVERROR(EIO);
138     pkt->stream_index = 0;
139     pkt->size = ret;
140
141     return 0;
142 }
143
144 AVInputFormat ff_sox_demuxer = {
145     "sox",
146     NULL_IF_CONFIG_SMALL("SoX native format"),
147     0,
148     sox_probe,
149     sox_read_header,
150     sox_read_packet,
151     NULL,
152     pcm_read_seek,
153 };