[FFmpeg-devel] [PATCH] IRCAM Sound Format demuxer
Daniel Verkamp
daniel
Tue Apr 20 20:03:33 CEST 2010
On Tue, Apr 20, 2010 at 1:02 AM, Jai Menon <jmenon86 at gmail.com> wrote:
> On Tue, Apr 20, 2010 at 9:29 AM, Daniel Verkamp <daniel at drv.nu> wrote:
>> ---
>> ?Changelog ? ? ? ? ? ? ? ?| ? ?1 +
>> ?doc/general.texi ? ? ? ? | ? ?1 +
>> ?libavformat/Makefile ? ? | ? ?1 +
>> ?libavformat/allformats.c | ? ?1 +
>> ?libavformat/avformat.h ? | ? ?2 +-
>> ?libavformat/ircamsf.c ? ?| ?200 ++++++++++++++++++++++++++++++++++++++++++++++
>> ?6 files changed, 205 insertions(+), 1 deletions(-)
>
> [...]
>
>> ?create mode 100644 libavformat/ircamsf.c
>> diff --git a/libavformat/ircamsf.c b/libavformat/ircamsf.c
>> new file mode 100644
>> index 0000000..3ce97f6
>> --- /dev/null
>> +++ b/libavformat/ircamsf.c
>> @@ -0,0 +1,200 @@
>> +/*
>> + * IRCAM SF demuxer
>> + * Copyright (c) 2010 Daniel Verkamp
>> + *
>> + * This file is part of FFmpeg.
>> + *
>> + * FFmpeg is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU Lesser General Public
>> + * License as published by the Free Software Foundation; either
>> + * version 2.1 of the License, or (at your option) any later version.
>> + *
>> + * FFmpeg is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ?See the GNU
>> + * Lesser General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU Lesser General Public
>> + * License along with FFmpeg; if not, write to the Free Software
>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
>> + */
>> +
>> +/**
>> + * IRCAM SF demuxer
>> + * @file libavformat/ircamsf.c
>> + * @author Daniel Verkamp
>> + * @sa http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/IRCAM/IRCAM.html
>> + */
>> +
>> +#include "avformat.h"
>> +#include "raw.h"
>> +#include "riff.h"
>> +#include "libavutil/intreadwrite.h"
>> +
>> +static const AVCodecTag generic_codec_tags[] = {
>> + ? ?{ CODEC_ID_PCM_S8, ? ?0x00001 },
>> + ? ?{ CODEC_ID_PCM_ALAW, ?0x10001 },
>> + ? ?{ CODEC_ID_PCM_MULAW, 0x20001 },
>> +};
>> +
>> +static const AVCodecTag le_codec_tags[] = {
>> + ? ?{ CODEC_ID_PCM_S16LE, 0x00002 },
>> + ? ?{ CODEC_ID_PCM_S24LE, 0x00003 },
>> + ? ?{ CODEC_ID_PCM_S32LE, 0x40004 },
>> + ? ?{ CODEC_ID_PCM_F32LE, 0x00004 },
>> + ? ?{ CODEC_ID_PCM_F64LE, 0x00008 },
>> +};
>> +
>> +static const AVCodecTag be_codec_tags[] = {
>> + ? ?{ CODEC_ID_PCM_S16BE, 0x00002 },
>> + ? ?{ CODEC_ID_PCM_S24BE, 0x00003 },
>> + ? ?{ CODEC_ID_PCM_S32BE, 0x40004 },
>> + ? ?{ CODEC_ID_PCM_F32BE, 0x00004 },
>> + ? ?{ CODEC_ID_PCM_F64BE, 0x00008 },
>> +};
>
> an additional CODEC_ID_NONE,0 is required in these tables.
>
Right, silly mistake, fixed.
> [...]
>
>> +static int identify(uint32_t tag)
>> +{
>> + ? ?int i;
>> +
>> + ? ?for (i = 0; i < sizeof(be_tags) / sizeof(*be_tags); i++)
>
> FF_ARRAY_ELEMS here and below
>
Aha, I knew that existed somewhere, but I couldn't find it...
> [...]
>
>> +static int probe(AVProbeData *p)
>> +{
>> + ? ?unsigned char *buf = p->buf;
>> + ? ?if (p->buf_size <= 16)
>> + ? ? ? ?return 0;
>> +
>> + ? ?if (identify(AV_RB32(buf)) < 0)
>> + ? ? ? ?return 0;
>> +
>> + ? ?if (!AV_RB32(buf + 4) || !AV_RB32(buf + 8) || !AV_RB32(buf + 12))
>> + ? ? ? ?return 0;
>> +
>> + ? ?return AVPROBE_SCORE_MAX;
>
> Could be fragile, is there anything else we could check? stream
> parameters perhaps?
>
I added a slightly better check here; anything more would be heuristics.
>> +}
>> +
>> +static int read_header(AVFormatContext *s, AVFormatParameters *ap)
>> +{
>> + ? ?ByteIOContext *pb = s->pb;
>> + ? ?AVStream *st;
>> + ? ?AVCodecContext *dec;
>> + ? ?const AVCodecTag *tags;
>> + ? ?uint32_t tag;
>> + ? ?int be, bits_per_frame, chunk, sz;
>> + ? ?char *comment;
>> +
>> + ? ?be = identify(get_be32(pb));
>> + ? ?if (be < 0)
>> + ? ? ? ?return AVERROR_INVALIDDATA;
>> +
>> + ? ?st = av_new_stream(s, 0);
>> + ? ?if (!st)
>> + ? ? ? ?return AVERROR(ENOMEM);
>> +
>> + ? ?dec = st->codec;
>> + ? ?dec->codec_type = AVMEDIA_TYPE_AUDIO;
>> +
>> + ? ?if (be) {
>> + ? ? ? ?dec->sample_rate = av_int2flt(get_be32(pb));
>> + ? ? ? ?dec->channels ? ?= get_be32(pb);
>> + ? ? ? ?tag ? ? ? ? ? ? ?= get_be32(pb);
>> + ? ? ? ?tags ? ? ? ? ? ? = be_codec_tags;
>> + ? ?} else {
>> + ? ? ? ?dec->sample_rate = av_int2flt(get_le32(pb));
>> + ? ? ? ?dec->channels ? ?= get_le32(pb);
>> + ? ? ? ?tag ? ? ? ? ? ? ?= get_le32(pb);
>> + ? ? ? ?tags ? ? ? ? ? ? = le_codec_tags;
>> + ? ?}
>> +
>> + ? ?if (dec->sample_rate <= 0) {
>> + ? ? ? ?av_log(s, AV_LOG_ERROR, "invalid sample rate %d\n", dec->sample_rate);
>> + ? ? ? ?return AVERROR_INVALIDDATA;
>> + ? ?}
>> +
>> + ? ?dec->codec_id = ff_codec_get_id(tags, tag);
>> + ? ?if (dec->codec_id == CODEC_ID_NONE)
>> + ? ? ? ?dec->codec_id = ff_codec_get_id(generic_codec_tags, tag);
>> +
>> + ? ?av_set_pts_info(st, 64, 1, dec->sample_rate);
>> +
>> + ? ?while (url_ftell(pb) < 1024) {
>> + ? ? ? ?if (be) {
>> + ? ? ? ? ? ?chunk = get_be16(pb);
>> + ? ? ? ? ? ?sz ? ?= get_be16(pb);
>> + ? ? ? ?} else {
>> + ? ? ? ? ? ?chunk = get_le16(pb);
>> + ? ? ? ? ? ?sz ? ?= get_le16(pb);
>> + ? ? ? ?}
>> +
>> + ? ? ? ?if (!chunk) // end chunk
>> + ? ? ? ? ? ?break;
>> +
>> + ? ? ? ?switch (chunk) {
>> + ? ? ? ?case 2: // comment
>> + ? ? ? ? ? ?comment = av_malloc(sz + 1);
>> + ? ? ? ? ? ?if (get_buffer(pb, comment, sz) != sz) {
>> + ? ? ? ? ? ? ? ?av_freep(&comment);
>> + ? ? ? ? ? ? ? ?return AVERROR(EIO);
>> + ? ? ? ? ? ?}
>> + ? ? ? ? ? ?comment[sz] = 0;
>> + ? ? ? ? ? ?av_metadata_set2(&s->metadata, "comment", comment,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? AV_METADATA_DONT_STRDUP_VAL);
>> + ? ? ? ? ? ?break;
>> + ? ? ? ?default:
>> + ? ? ? ? ? ?url_fskip(pb, sz);
>> + ? ? ? ? ? ?break;
>> + ? ? ? ?}
>> + ? ?}
>> +
>> + ? ?url_fseek(pb, 1024, SEEK_SET);
>
> Could this be avoided, by skipping the padding bytes instead?
>
By my reading of the url_fseek() code, this already happens
internally, but I could be wrong. I specifically made it a seek and
not a skip in case the previous loop overreads into the sample data.
>> +
>> + ? ?dec->bits_per_coded_sample = av_get_bits_per_sample(dec->codec_id);
>> + ? ?bits_per_frame ? = dec->channels * dec->bits_per_coded_sample;
>> + ? ?dec->block_align = bits_per_frame >> 3;
>> + ? ?dec->bit_rate ? ?= bits_per_frame * dec->sample_rate;
>> +
>> + ? ?return 0;
>> +}
>> +
>> +#define NUM_SAMPLES 1024
>> +
>> +static int read_packet(AVFormatContext *s, AVPacket *pkt)
>> +{
>> + ? ?return av_get_packet(s->pb, pkt,
>> + ? ? ? ? ? ? ? ? ? ? ? ? NUM_SAMPLES * s->streams[0]->codec->block_align);
>> +}
>
> looks like raw_read_packet could be used but maybe I'm missing something
>
I suppose so, although it does pts/dts calculations that don't seem
necessary, and it would need to be made non-static.
> --
> Jai Menon
Thanks for the review.
-- Daniel Verkamp
-------------- next part --------------
>From 0ad446191bc9e0b962235a6378245d7666ae4e7f Mon Sep 17 00:00:00 2001
From: Daniel Verkamp <daniel at drv.nu>
Date: Mon, 19 Apr 2010 23:26:19 -0400
Subject: [PATCH] IRCAM Sound Format demuxer
---
Changelog | 1 +
doc/general.texi | 1 +
libavformat/Makefile | 1 +
libavformat/allformats.c | 1 +
libavformat/avformat.h | 2 +-
libavformat/ircamsf.c | 225 ++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 230 insertions(+), 1 deletions(-)
create mode 100644 libavformat/ircamsf.c
diff --git a/Changelog b/Changelog
index c454c15..7ad100f 100644
--- a/Changelog
+++ b/Changelog
@@ -70,6 +70,7 @@ version <next>:
- Psygnosis YOP demuxer and video decoder
- spectral extension support in the E-AC-3 decoder
- unsharp video filter
+- IRCAM Sound Format (.sf) demuxer
diff --git a/doc/general.texi b/doc/general.texi
index 1bfde02..8dfb07c 100644
--- a/doc/general.texi
+++ b/doc/general.texi
@@ -107,6 +107,7 @@ library:
@tab Interchange File Format
@item Interplay MVE @tab @tab X
@tab Format used in various Interplay computer games.
+ at item IRCAM Sound Format (.sf) @tab @tab X
@item IV8 @tab @tab X
@tab A format generated by IndigoVision 8000 video server.
@item LMLM4 @tab @tab X
diff --git a/libavformat/Makefile b/libavformat/Makefile
index 43a4a2e..e7e1205 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -96,6 +96,7 @@ OBJS-$(CONFIG_IMAGE2PIPE_DEMUXER) += img2.o
OBJS-$(CONFIG_IMAGE2PIPE_MUXER) += img2.o
OBJS-$(CONFIG_INGENIENT_DEMUXER) += raw.o
OBJS-$(CONFIG_IPMOVIE_DEMUXER) += ipmovie.o
+OBJS-$(CONFIG_IRCAMSF_DEMUXER) += ircamsf.o raw.o
OBJS-$(CONFIG_ISS_DEMUXER) += iss.o
OBJS-$(CONFIG_IV8_DEMUXER) += iv8.o
OBJS-$(CONFIG_LMLM4_DEMUXER) += lmlm4.o
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index 27dba10..d048549 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -102,6 +102,7 @@ void av_register_all(void)
REGISTER_DEMUXER (INGENIENT, ingenient);
REGISTER_DEMUXER (IPMOVIE, ipmovie);
REGISTER_MUXER (IPOD, ipod);
+ REGISTER_DEMUXER (IRCAMSF, ircamsf);
REGISTER_DEMUXER (ISS, iss);
REGISTER_DEMUXER (IV8, iv8);
REGISTER_DEMUXER (LMLM4, lmlm4);
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 5ff08c0..09d176d 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -22,7 +22,7 @@
#define AVFORMAT_AVFORMAT_H
#define LIBAVFORMAT_VERSION_MAJOR 52
-#define LIBAVFORMAT_VERSION_MINOR 61
+#define LIBAVFORMAT_VERSION_MINOR 62
#define LIBAVFORMAT_VERSION_MICRO 0
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
diff --git a/libavformat/ircamsf.c b/libavformat/ircamsf.c
new file mode 100644
index 0000000..7892e31
--- /dev/null
+++ b/libavformat/ircamsf.c
@@ -0,0 +1,225 @@
+/*
+ * IRCAM SF demuxer
+ * Copyright (c) 2010 Daniel Verkamp
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * IRCAM SF demuxer
+ * @file libavformat/ircamsf.c
+ * @author Daniel Verkamp
+ * @sa http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/IRCAM/IRCAM.html
+ */
+
+#include "avformat.h"
+#include "raw.h"
+#include "riff.h"
+#include "libavutil/intreadwrite.h"
+
+static const AVCodecTag generic_codec_tags[] = {
+ { CODEC_ID_PCM_S8, 0x00001 },
+ { CODEC_ID_PCM_ALAW, 0x10001 },
+ { CODEC_ID_PCM_MULAW, 0x20001 },
+ { CODEC_ID_NONE, 0 },
+};
+
+static const AVCodecTag le_codec_tags[] = {
+ { CODEC_ID_PCM_S16LE, 0x00002 },
+ { CODEC_ID_PCM_S24LE, 0x00003 },
+ { CODEC_ID_PCM_S32LE, 0x40004 },
+ { CODEC_ID_PCM_F32LE, 0x00004 },
+ { CODEC_ID_PCM_F64LE, 0x00008 },
+ { CODEC_ID_NONE, 0 },
+};
+
+static const AVCodecTag be_codec_tags[] = {
+ { CODEC_ID_PCM_S16BE, 0x00002 },
+ { CODEC_ID_PCM_S24BE, 0x00003 },
+ { CODEC_ID_PCM_S32BE, 0x40004 },
+ { CODEC_ID_PCM_F32BE, 0x00004 },
+ { CODEC_ID_PCM_F64BE, 0x00008 },
+ { CODEC_ID_NONE, 0 },
+};
+
+static const uint32_t be_tags[] = {
+ 0x64A30200, // Sun (native)
+ 0x64A30400, // NeXT
+ 0x0001A364, // VAX
+ 0x0003A364, // MIPS (SGI)
+};
+
+static const uint32_t le_tags[] = {
+ 0x64A30100, // VAX (native)
+ 0x64A30300, // MIPS (DECstation)
+ 0x0002A364, // Sun
+};
+
+static int identify(uint32_t tag)
+{
+ int i;
+
+ for (i = 0; i < FF_ARRAY_ELEMS(be_tags); i++)
+ if (be_tags[i] == tag)
+ return 1;
+
+ for (i = 0; i < FF_ARRAY_ELEMS(le_tags); i++)
+ if (le_tags[i] == tag)
+ return 0;
+
+ return -1;
+}
+
+static enum CodecID get_codec(uint32_t tag, int be)
+{
+ const AVCodecTag *tags = be ? be_codec_tags : le_codec_tags;
+ enum CodecID codec_id = ff_codec_get_id(tags, tag);
+ if (codec_id == CODEC_ID_NONE)
+ codec_id = ff_codec_get_id(generic_codec_tags, tag);
+ return codec_id;
+}
+
+static int probe(AVProbeData *p)
+{
+ unsigned char *buf = p->buf;
+ int be, channels, sample_rate;
+ uint32_t tag;
+
+ if (p->buf_size <= 16)
+ return 0;
+
+ be = identify(AV_RB32(buf));
+ if (be < 0)
+ return 0;
+
+ if (be) {
+ sample_rate = av_int2flt(AV_RB32(buf + 4));
+ channels = AV_RB32(buf + 8);
+ tag = AV_RB32(buf + 12);
+ } else {
+ sample_rate = av_int2flt(AV_RL32(buf + 4));
+ channels = AV_RL32(buf + 8);
+ tag = AV_RL32(buf + 12);
+ }
+
+ if (sample_rate <= 0 || channels <= 0 || channels > 256)
+ return 0;
+
+ tag = be ? AV_RB32(buf + 12) : AV_RL32(buf + 12);
+ if (get_codec(tag, be) == CODEC_ID_NONE)
+ return 0;
+
+ return AVPROBE_SCORE_MAX;
+}
+
+static int read_header(AVFormatContext *s, AVFormatParameters *ap)
+{
+ ByteIOContext *pb = s->pb;
+ AVStream *st;
+ AVCodecContext *dec;
+ uint32_t tag;
+ int be, bits_per_frame, chunk, sz;
+ char *comment;
+
+ be = identify(get_be32(pb));
+ if (be < 0)
+ return AVERROR_INVALIDDATA;
+
+ st = av_new_stream(s, 0);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ dec = st->codec;
+ dec->codec_type = AVMEDIA_TYPE_AUDIO;
+
+ if (be) {
+ dec->sample_rate = av_int2flt(get_be32(pb));
+ dec->channels = get_be32(pb);
+ tag = get_be32(pb);
+ } else {
+ dec->sample_rate = av_int2flt(get_le32(pb));
+ dec->channels = get_le32(pb);
+ tag = get_le32(pb);
+ }
+
+ if (dec->sample_rate <= 0) {
+ av_log(s, AV_LOG_ERROR, "invalid sample rate %d\n", dec->sample_rate);
+ return AVERROR_INVALIDDATA;
+ }
+
+ dec->codec_id = get_codec(tag, be);
+
+ av_set_pts_info(st, 64, 1, dec->sample_rate);
+
+ while (url_ftell(pb) < 1024) {
+ if (be) {
+ chunk = get_be16(pb);
+ sz = get_be16(pb);
+ } else {
+ chunk = get_le16(pb);
+ sz = get_le16(pb);
+ }
+
+ if (!chunk) // end chunk
+ break;
+
+ switch (chunk) {
+ case 2: // comment
+ comment = av_malloc(sz + 1);
+ if (get_buffer(pb, comment, sz) != sz) {
+ av_freep(&comment);
+ return AVERROR(EIO);
+ }
+ comment[sz] = 0;
+ av_metadata_set2(&s->metadata, "comment", comment,
+ AV_METADATA_DONT_STRDUP_VAL);
+ break;
+ default:
+ url_fskip(pb, sz);
+ break;
+ }
+ }
+
+ url_fseek(pb, 1024, SEEK_SET);
+
+ dec->bits_per_coded_sample = av_get_bits_per_sample(dec->codec_id);
+ bits_per_frame = dec->channels * dec->bits_per_coded_sample;
+ dec->block_align = bits_per_frame >> 3;
+ dec->bit_rate = bits_per_frame * dec->sample_rate;
+
+ return 0;
+}
+
+#define NUM_SAMPLES 1024
+
+static int read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ return av_get_packet(s->pb, pkt,
+ NUM_SAMPLES * s->streams[0]->codec->block_align);
+}
+
+AVInputFormat ircamsf_demuxer = {
+ "ircamsf",
+ NULL_IF_CONFIG_SMALL("IRCAM Sound Format"),
+ 0,
+ probe,
+ read_header,
+ read_packet,
+ NULL,
+ pcm_read_seek,
+ .flags = AVFMT_GENERIC_INDEX,
+};
--
1.7.0.2
More information about the ffmpeg-devel
mailing list