Sample files are available at https://archive.org/download/datstrue-read/
From 50c78a0ae2049e2dbd65e2c3d28f3d8abea1adfa Mon Sep 17 00:00:00 2001 From: Paul B Mahol <one...@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
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".