Patch by Daniel Verkamp $firstname@drv DOT nu.
Originally committed as revision 18998 to svn://svn.ffmpeg.org/ffmpeg/trunk
... | ... |
@@ -209,6 +209,7 @@ library: |
209 | 209 |
@item Sony OpenMG (OMA) @tab @tab X |
210 | 210 |
@tab Audio format used in Sony Sonic Stage and Sony Vegas. |
211 | 211 |
@item Sony PlayStation STR @tab @tab X |
212 |
+@item SoX native format @tab X @tab X |
|
212 | 213 |
@item SUN AU format @tab X @tab X |
213 | 214 |
@item THP @tab @tab X |
214 | 215 |
@tab Used on the Nintendo GameCube. |
... | ... |
@@ -204,6 +204,8 @@ OBJS-$(CONFIG_SHORTEN_DEMUXER) += raw.o id3v2.o |
204 | 204 |
OBJS-$(CONFIG_SIFF_DEMUXER) += siff.o |
205 | 205 |
OBJS-$(CONFIG_SMACKER_DEMUXER) += smacker.o |
206 | 206 |
OBJS-$(CONFIG_SOL_DEMUXER) += sol.o raw.o |
207 |
+OBJS-$(CONFIG_SOX_DEMUXER) += soxdec.o |
|
208 |
+OBJS-$(CONFIG_SOX_MUXER) += soxenc.o |
|
207 | 209 |
OBJS-$(CONFIG_STR_DEMUXER) += psxstr.o |
208 | 210 |
OBJS-$(CONFIG_SWF_DEMUXER) += swfdec.o |
209 | 211 |
OBJS-$(CONFIG_SWF_MUXER) += swfenc.o |
... | ... |
@@ -177,6 +177,7 @@ void av_register_all(void) |
177 | 177 |
REGISTER_DEMUXER (SIFF, siff); |
178 | 178 |
REGISTER_DEMUXER (SMACKER, smacker); |
179 | 179 |
REGISTER_DEMUXER (SOL, sol); |
180 |
+ REGISTER_MUXDEMUX (SOX, sox); |
|
180 | 181 |
REGISTER_DEMUXER (STR, str); |
181 | 182 |
REGISTER_MUXDEMUX (SWF, swf); |
182 | 183 |
REGISTER_MUXER (TG2, tg2); |
183 | 184 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,29 @@ |
0 |
+/* |
|
1 |
+ * SoX native format common data |
|
2 |
+ * Copyright (c) 2009 Daniel Verkamp <daniel@drv.nu> |
|
3 |
+ * |
|
4 |
+ * This file is part of FFmpeg. |
|
5 |
+ * |
|
6 |
+ * FFmpeg is free software; you can redistribute it and/or |
|
7 |
+ * modify it under the terms of the GNU Lesser General Public |
|
8 |
+ * License as published by the Free Software Foundation; either |
|
9 |
+ * version 2.1 of the License, or (at your option) any later version. |
|
10 |
+ * |
|
11 |
+ * FFmpeg is distributed in the hope that it will be useful, |
|
12 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
14 |
+ * Lesser General Public License for more details. |
|
15 |
+ * |
|
16 |
+ * You should have received a copy of the GNU Lesser General Public |
|
17 |
+ * License along with FFmpeg; if not, write to the Free Software |
|
18 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
19 |
+ */ |
|
20 |
+ |
|
21 |
+#ifndef AVFORMAT_SOX_H |
|
22 |
+#define AVFORMAT_SOX_H |
|
23 |
+ |
|
24 |
+#define SOX_FIXED_HDR (4 + 8 + 8 + 4 + 4) /**< Size of fixed header without magic */ |
|
25 |
+ |
|
26 |
+#define SOX_TAG MKTAG('.', 'S', 'o', 'X') |
|
27 |
+ |
|
28 |
+#endif /* AVFORMAT_SOX_H */ |
0 | 29 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,149 @@ |
0 |
+/* |
|
1 |
+ * SoX native format demuxer |
|
2 |
+ * Copyright (c) 2009 Daniel Verkamp <daniel@drv.nu> |
|
3 |
+ * |
|
4 |
+ * Based on libSoX sox-fmt.c |
|
5 |
+ * Copyright (c) 2008 robs@users.sourceforge.net |
|
6 |
+ * |
|
7 |
+ * This file is part of FFmpeg. |
|
8 |
+ * |
|
9 |
+ * FFmpeg is free software; you can redistribute it and/or |
|
10 |
+ * modify it under the terms of the GNU Lesser General Public |
|
11 |
+ * License as published by the Free Software Foundation; either |
|
12 |
+ * version 2.1 of the License, or (at your option) any later version. |
|
13 |
+ * |
|
14 |
+ * FFmpeg is distributed in the hope that it will be useful, |
|
15 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
16 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
17 |
+ * Lesser General Public License for more details. |
|
18 |
+ * |
|
19 |
+ * You should have received a copy of the GNU Lesser General Public |
|
20 |
+ * License along with FFmpeg; if not, write to the Free Software |
|
21 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
22 |
+ */ |
|
23 |
+ |
|
24 |
+/** |
|
25 |
+ * SoX native format demuxer |
|
26 |
+ * @file libavformat/soxdec.c |
|
27 |
+ * @author Daniel Verkamp |
|
28 |
+ * @sa http://wiki.multimedia.cx/index.php?title=SoX_native_intermediate_format |
|
29 |
+ */ |
|
30 |
+ |
|
31 |
+#include "libavutil/intreadwrite.h" |
|
32 |
+#include "avformat.h" |
|
33 |
+#include "raw.h" |
|
34 |
+#include "sox.h" |
|
35 |
+ |
|
36 |
+static int sox_probe(AVProbeData *p) |
|
37 |
+{ |
|
38 |
+ if (AV_RL32(p->buf) == SOX_TAG || AV_RB32(p->buf) == SOX_TAG) |
|
39 |
+ return AVPROBE_SCORE_MAX; |
|
40 |
+ return 0; |
|
41 |
+} |
|
42 |
+ |
|
43 |
+static int sox_read_header(AVFormatContext *s, |
|
44 |
+ AVFormatParameters *ap) |
|
45 |
+{ |
|
46 |
+ ByteIOContext *pb = s->pb; |
|
47 |
+ unsigned header_size, comment_size; |
|
48 |
+ double sample_rate, sample_rate_frac; |
|
49 |
+ AVStream *st; |
|
50 |
+ |
|
51 |
+ st = av_new_stream(s, 0); |
|
52 |
+ if (!st) |
|
53 |
+ return AVERROR(ENOMEM); |
|
54 |
+ |
|
55 |
+ st->codec->codec_type = CODEC_TYPE_AUDIO; |
|
56 |
+ |
|
57 |
+ if (get_le32(pb) == SOX_TAG) { |
|
58 |
+ st->codec->codec_id = CODEC_ID_PCM_S32LE; |
|
59 |
+ header_size = get_le32(pb); |
|
60 |
+ url_fskip(pb, 8); /* sample count */ |
|
61 |
+ sample_rate = av_int2dbl(get_le64(pb)); |
|
62 |
+ st->codec->channels = get_le32(pb); |
|
63 |
+ comment_size = get_le32(pb); |
|
64 |
+ } else { |
|
65 |
+ st->codec->codec_id = CODEC_ID_PCM_S32BE; |
|
66 |
+ header_size = get_be32(pb); |
|
67 |
+ url_fskip(pb, 8); /* sample count */ |
|
68 |
+ sample_rate = av_int2dbl(get_be64(pb)); |
|
69 |
+ st->codec->channels = get_be32(pb); |
|
70 |
+ comment_size = get_be32(pb); |
|
71 |
+ } |
|
72 |
+ |
|
73 |
+ if (comment_size > 0xFFFFFFFFU - SOX_FIXED_HDR - 4U) { |
|
74 |
+ av_log(s, AV_LOG_ERROR, "invalid comment size (%u)\n", comment_size); |
|
75 |
+ return -1; |
|
76 |
+ } |
|
77 |
+ |
|
78 |
+ if (sample_rate <= 0 || sample_rate > INT_MAX) { |
|
79 |
+ av_log(s, AV_LOG_ERROR, "invalid sample rate (%f)\n", sample_rate); |
|
80 |
+ return -1; |
|
81 |
+ } |
|
82 |
+ |
|
83 |
+ sample_rate_frac = sample_rate - floor(sample_rate); |
|
84 |
+ if (sample_rate_frac) |
|
85 |
+ av_log(s, AV_LOG_WARNING, |
|
86 |
+ "truncating fractional part of sample rate (%f)\n", |
|
87 |
+ sample_rate_frac); |
|
88 |
+ |
|
89 |
+ if ((header_size + 4) & 7 || header_size < SOX_FIXED_HDR + comment_size |
|
90 |
+ || st->codec->channels > 65535) /* Reserve top 16 bits */ { |
|
91 |
+ av_log(s, AV_LOG_ERROR, "invalid header\n"); |
|
92 |
+ return -1; |
|
93 |
+ } |
|
94 |
+ |
|
95 |
+ if (comment_size && |
|
96 |
+ comment_size + FF_INPUT_BUFFER_PADDING_SIZE >= comment_size) { |
|
97 |
+ char *comment = av_mallocz(comment_size + FF_INPUT_BUFFER_PADDING_SIZE); |
|
98 |
+ if (get_buffer(pb, comment, comment_size) != comment_size) { |
|
99 |
+ av_freep(&comment); |
|
100 |
+ return AVERROR_IO; |
|
101 |
+ } |
|
102 |
+ av_metadata_set(&s->metadata, "comment", comment); |
|
103 |
+ av_freep(&comment); |
|
104 |
+ } |
|
105 |
+ |
|
106 |
+ url_fskip(pb, header_size - SOX_FIXED_HDR - comment_size); |
|
107 |
+ |
|
108 |
+ st->codec->sample_rate = sample_rate; |
|
109 |
+ st->codec->sample_fmt = SAMPLE_FMT_S32; |
|
110 |
+ st->codec->bits_per_coded_sample = 32; |
|
111 |
+ st->codec->bit_rate = st->codec->sample_rate * |
|
112 |
+ st->codec->bits_per_coded_sample * |
|
113 |
+ st->codec->channels; |
|
114 |
+ |
|
115 |
+ av_set_pts_info(st, 64, 1, st->codec->sample_rate); |
|
116 |
+ |
|
117 |
+ return 0; |
|
118 |
+} |
|
119 |
+ |
|
120 |
+#define MAX_SIZE 4096 |
|
121 |
+ |
|
122 |
+static int sox_read_packet(AVFormatContext *s, |
|
123 |
+ AVPacket *pkt) |
|
124 |
+{ |
|
125 |
+ int ret; |
|
126 |
+ |
|
127 |
+ if (url_feof(s->pb)) |
|
128 |
+ return AVERROR_EOF; |
|
129 |
+ |
|
130 |
+ ret = av_get_packet(s->pb, pkt, MAX_SIZE); |
|
131 |
+ if (ret < 0) |
|
132 |
+ return AVERROR(EIO); |
|
133 |
+ pkt->stream_index = 0; |
|
134 |
+ pkt->size = ret; |
|
135 |
+ |
|
136 |
+ return 0; |
|
137 |
+} |
|
138 |
+ |
|
139 |
+AVInputFormat sox_demuxer = { |
|
140 |
+ "sox", |
|
141 |
+ NULL_IF_CONFIG_SMALL("SoX native format"), |
|
142 |
+ 0, |
|
143 |
+ sox_probe, |
|
144 |
+ sox_read_header, |
|
145 |
+ sox_read_packet, |
|
146 |
+ NULL, |
|
147 |
+ pcm_read_seek, |
|
148 |
+}; |
0 | 149 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,126 @@ |
0 |
+/* |
|
1 |
+ * SoX native format muxer |
|
2 |
+ * Copyright (c) 2009 Daniel Verkamp <daniel@drv.nu> |
|
3 |
+ * |
|
4 |
+ * Based on libSoX sox-fmt.c |
|
5 |
+ * Copyright (c) 2008 robs@users.sourceforge.net |
|
6 |
+ * |
|
7 |
+ * This file is part of FFmpeg. |
|
8 |
+ * |
|
9 |
+ * FFmpeg is free software; you can redistribute it and/or |
|
10 |
+ * modify it under the terms of the GNU Lesser General Public |
|
11 |
+ * License as published by the Free Software Foundation; either |
|
12 |
+ * version 2.1 of the License, or (at your option) any later version. |
|
13 |
+ * |
|
14 |
+ * FFmpeg is distributed in the hope that it will be useful, |
|
15 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
16 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
17 |
+ * Lesser General Public License for more details. |
|
18 |
+ * |
|
19 |
+ * You should have received a copy of the GNU Lesser General Public |
|
20 |
+ * License along with FFmpeg; if not, write to the Free Software |
|
21 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
22 |
+ */ |
|
23 |
+ |
|
24 |
+/** |
|
25 |
+ * SoX native format muxer |
|
26 |
+ * @file libavformat/soxenc.c |
|
27 |
+ * @author Daniel Verkamp |
|
28 |
+ * @sa http://wiki.multimedia.cx/index.php?title=SoX_native_intermediate_format |
|
29 |
+ */ |
|
30 |
+ |
|
31 |
+#include "libavutil/intreadwrite.h" |
|
32 |
+#include "avformat.h" |
|
33 |
+#include "sox.h" |
|
34 |
+ |
|
35 |
+typedef struct { |
|
36 |
+ int64_t header_size; |
|
37 |
+} SoXContext; |
|
38 |
+ |
|
39 |
+static int sox_write_header(AVFormatContext *s) |
|
40 |
+{ |
|
41 |
+ SoXContext *sox = s->priv_data; |
|
42 |
+ ByteIOContext *pb = s->pb; |
|
43 |
+ AVCodecContext *enc = s->streams[0]->codec; |
|
44 |
+ AVMetadataTag *comment; |
|
45 |
+ size_t comment_len = 0, comment_size; |
|
46 |
+ |
|
47 |
+ comment = av_metadata_get(s->metadata, "comment", NULL, 0); |
|
48 |
+ if (comment) |
|
49 |
+ comment_len = strlen(comment->value); |
|
50 |
+ comment_size = (comment_len + 7) & ~7; |
|
51 |
+ |
|
52 |
+ sox->header_size = SOX_FIXED_HDR + comment_size; |
|
53 |
+ |
|
54 |
+ if (enc->codec_id == CODEC_ID_PCM_S32LE) { |
|
55 |
+ put_tag(pb, ".SoX"); |
|
56 |
+ put_le32(pb, sox->header_size); |
|
57 |
+ put_le64(pb, 0); /* number of samples */ |
|
58 |
+ put_le64(pb, av_dbl2int(enc->sample_rate)); |
|
59 |
+ put_le32(pb, enc->channels); |
|
60 |
+ put_le32(pb, comment_size); |
|
61 |
+ } else if (enc->codec_id == CODEC_ID_PCM_S32BE) { |
|
62 |
+ put_tag(pb, "XoS."); |
|
63 |
+ put_be32(pb, sox->header_size); |
|
64 |
+ put_be64(pb, 0); /* number of samples */ |
|
65 |
+ put_be64(pb, av_dbl2int(enc->sample_rate)); |
|
66 |
+ put_be32(pb, enc->channels); |
|
67 |
+ put_be32(pb, comment_size); |
|
68 |
+ } else { |
|
69 |
+ av_log(s, AV_LOG_ERROR, "invalid codec; use pcm_s32le or pcm_s32be\n"); |
|
70 |
+ return -1; |
|
71 |
+ } |
|
72 |
+ |
|
73 |
+ if (comment_len) |
|
74 |
+ put_buffer(pb, comment->value, comment_len); |
|
75 |
+ |
|
76 |
+ for ( ; comment_size > comment_len; comment_len++) |
|
77 |
+ put_byte(pb, 0); |
|
78 |
+ |
|
79 |
+ put_flush_packet(pb); |
|
80 |
+ |
|
81 |
+ return 0; |
|
82 |
+} |
|
83 |
+ |
|
84 |
+static int sox_write_packet(AVFormatContext *s, AVPacket *pkt) |
|
85 |
+{ |
|
86 |
+ ByteIOContext *pb = s->pb; |
|
87 |
+ put_buffer(pb, pkt->data, pkt->size); |
|
88 |
+ return 0; |
|
89 |
+} |
|
90 |
+ |
|
91 |
+static int sox_write_trailer(AVFormatContext *s) |
|
92 |
+{ |
|
93 |
+ SoXContext *sox = s->priv_data; |
|
94 |
+ ByteIOContext *pb = s->pb; |
|
95 |
+ AVCodecContext *enc = s->streams[0]->codec; |
|
96 |
+ |
|
97 |
+ if (!url_is_streamed(s->pb)) { |
|
98 |
+ /* update number of samples */ |
|
99 |
+ int64_t file_size = url_ftell(pb); |
|
100 |
+ int64_t num_samples = (file_size - sox->header_size - 4LL) >> 2LL; |
|
101 |
+ url_fseek(pb, 8, SEEK_SET); |
|
102 |
+ if (enc->codec_id == CODEC_ID_PCM_S32LE) { |
|
103 |
+ put_le64(pb, num_samples); |
|
104 |
+ } else |
|
105 |
+ put_be64(pb, num_samples); |
|
106 |
+ url_fseek(pb, file_size, SEEK_SET); |
|
107 |
+ |
|
108 |
+ put_flush_packet(pb); |
|
109 |
+ } |
|
110 |
+ |
|
111 |
+ return 0; |
|
112 |
+} |
|
113 |
+ |
|
114 |
+AVOutputFormat sox_muxer = { |
|
115 |
+ "sox", |
|
116 |
+ NULL_IF_CONFIG_SMALL("SoX native format"), |
|
117 |
+ NULL, |
|
118 |
+ "sox", |
|
119 |
+ sizeof(SoXContext), |
|
120 |
+ CODEC_ID_PCM_S32LE, |
|
121 |
+ CODEC_ID_NONE, |
|
122 |
+ sox_write_header, |
|
123 |
+ sox_write_packet, |
|
124 |
+ sox_write_trailer, |
|
125 |
+}; |