[FFmpeg-devel] [PATCH] avformat: add DAT (Digital Audio Tape) demuxer
Jerome Martinez
jerome at mediaarea.net
Fri Jan 17 13:38:02 EET 2025
Sample files are available at https://archive.org/download/datstrue-read/
-------------- next part --------------
From 50c78a0ae2049e2dbd65e2c3d28f3d8abea1adfa Mon Sep 17 00:00:00 2001
From: Paul B Mahol <onemda at gmail.com>
Date: Thu, 12 Sep 2024 20:34:22 +0200
Subject: [PATCH] avformat: add DAT demuxer
---
libavformat/Makefile | 1 +
libavformat/allformats.c | 1 +
libavformat/dat.c | 159 +++++++++++++++++++++++++++++++++++++++
3 files changed, 161 insertions(+)
create mode 100644 libavformat/dat.c
diff --git a/libavformat/Makefile b/libavformat/Makefile
index 074efc118a..51839bba5e 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -172,6 +172,7 @@ OBJS-$(CONFIG_CODEC2RAW_DEMUXER) += codec2.o pcm.o
OBJS-$(CONFIG_CODEC2RAW_MUXER) += rawenc.o
OBJS-$(CONFIG_CONCAT_DEMUXER) += concatdec.o
OBJS-$(CONFIG_CRC_MUXER) += crcenc.o
+OBJS-$(CONFIG_DAT_DEMUXER) += dat.o
OBJS-$(CONFIG_DATA_DEMUXER) += rawdec.o
OBJS-$(CONFIG_DATA_MUXER) += rawenc.o
OBJS-$(CONFIG_DASH_MUXER) += dash.o dashenc.o hlsplaylist.o
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index 445f13f42a..b91ea45f65 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -129,6 +129,7 @@ extern const FFInputFormat ff_concat_demuxer;
extern const FFOutputFormat ff_crc_muxer;
extern const FFInputFormat ff_dash_demuxer;
extern const FFOutputFormat ff_dash_muxer;
+extern const FFInputFormat ff_dat_demuxer;
extern const FFInputFormat ff_data_demuxer;
extern const FFOutputFormat ff_data_muxer;
extern const FFInputFormat ff_daud_demuxer;
diff --git a/libavformat/dat.c b/libavformat/dat.c
new file mode 100644
index 0000000000..37548a8a73
--- /dev/null
+++ b/libavformat/dat.c
@@ -0,0 +1,159 @@
+/*
+ * DAT (Digital Audio Tape) demuxer
+ * Copyright (c) 2024 Paul B Mahol
+ *
+ * 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
+ */
+
+#include "avformat.h"
+#include "demux.h"
+#include "internal.h"
+
+#define DAT_PACKET_SIZE 5822
+#define DAT_OFFSET 5760
+
+static const uint32_t encoded_rate[] = { 48000, 44100, 32000, 0 };
+static const uint16_t encoded_size[] = { 5760, 5292, 3840, 0 };
+static const uint8_t encoded_chans[] = { 2, 4, 0, 0 };
+static const enum AVCodecID encoded_codec[] = {
+ AV_CODEC_ID_PCM_S16LE,
+ AV_CODEC_ID_NONE, AV_CODEC_ID_NONE, AV_CODEC_ID_NONE,
+};
+
+static int valid_frame(uint8_t *frame)
+{
+ uint8_t *scode = frame+DAT_OFFSET;
+ uint8_t *subid = scode+7*8;
+ uint8_t *mainid = subid+4;
+ int chan_index = (mainid[0] >> 0) & 0x3;
+ int rate_index = (mainid[0] >> 2) & 0x3;
+ int enc_index = (mainid[1] >> 6) & 0x3;
+ int dataid = (subid[0] >> 0) & 0xf;
+
+ if (dataid != 0 || encoded_codec[enc_index] == AV_CODEC_ID_NONE ||
+ encoded_chans[chan_index] == 0 ||
+ encoded_rate[rate_index] == 0)
+ return 0;
+
+ return 1;
+}
+
+static int read_probe(const AVProbeData *p)
+{
+ const int cnt = p->buf_size / DAT_PACKET_SIZE;
+ int score = 0;
+
+ for (int i = 0; i < cnt; i++) {
+ const int ret = valid_frame(&p->buf[i * DAT_PACKET_SIZE]);
+
+ score += ret;
+ if (ret == 0)
+ break;
+ }
+
+ return FFMIN(score, AVPROBE_SCORE_MAX);
+}
+
+static int read_header(AVFormatContext *s)
+{
+ s->ctx_flags |= AVFMTCTX_NOHEADER;
+
+ return 0;
+}
+
+static int parse_frame(uint8_t *frame, AVCodecParameters *par)
+{
+ uint8_t *scode = frame+DAT_OFFSET;
+ uint8_t *subid = scode+7*8;
+ uint8_t *mainid = subid+4;
+ int chan_index = (mainid[0] >> 0) & 0x3;
+ int rate_index = (mainid[0] >> 2) & 0x3;
+ int enc_index = (mainid[1] >> 6) & 0x3;
+ int dataid = (subid[0] >> 0) & 0xf;
+
+ par->codec_type = AVMEDIA_TYPE_AUDIO;
+ par->codec_id = encoded_codec[enc_index];
+ av_channel_layout_default(&par->ch_layout, encoded_chans[chan_index]);
+ par->sample_rate = encoded_rate[rate_index];
+ par->bit_rate = (8LL * DAT_PACKET_SIZE * par->sample_rate) / FFMAX(1, av_get_audio_frame_duration2(par, encoded_size[rate_index]));
+
+ if (dataid != 0 || par->codec_id == AV_CODEC_ID_NONE ||
+ par->ch_layout.nb_channels <= 0 ||
+ par->sample_rate <= 0)
+ return AVERROR_INVALIDDATA;
+
+ return encoded_size[rate_index];
+}
+
+static int read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ uint8_t data[DAT_PACKET_SIZE];
+ AVIOContext *pb = s->pb;
+ int ret, pcm_size;
+ int64_t pos;
+
+ if (avio_feof(pb))
+ return AVERROR_EOF;
+
+ pos = avio_tell(pb);
+ if (avio_read(pb, data, sizeof(data)) != sizeof(data))
+ return AVERROR_EOF;
+
+ if (s->nb_streams == 0) {
+ AVStream *st;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ pcm_size = parse_frame(data, st->codecpar);
+
+ avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
+ } else {
+ int old_sample_rate = s->streams[0]->codecpar->sample_rate;
+
+ pcm_size = parse_frame(data, s->streams[0]->codecpar);
+
+ if (old_sample_rate != s->streams[0]->codecpar->sample_rate) {
+ ret = ff_add_param_change(pkt, 0, 0, s->streams[0]->codecpar->sample_rate, 0, 0);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ if (pcm_size < 0)
+ return 0;
+
+ if ((ret = av_new_packet(pkt, pcm_size)) < 0)
+ return ret;
+ memcpy(pkt->data, data, pcm_size);
+
+ pkt->stream_index = 0;
+ pkt->pos = pos;
+
+ return 0;
+}
+
+const FFInputFormat ff_dat_demuxer = {
+ .p.name = "dat",
+ .p.long_name = NULL_IF_CONFIG_SMALL("DAT (Digital Audio Tape)"),
+ .p.flags = AVFMT_GENERIC_INDEX,
+ .p.extensions = "dat",
+ .read_probe = read_probe,
+ .read_header = read_header,
+ .read_packet = read_packet,
+};
--
2.46.0.windows.1
More information about the ffmpeg-devel
mailing list