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 |
+}; |