[FFmpeg-devel] [PATCH 3/7] avformat/s337m: switch to two rawdec for 16- and 24-bit

ffnicolasg at sfr.fr ffnicolasg at sfr.fr
Wed Dec 4 16:14:05 EET 2024


From: Nicolas Gaullier <nicolas.gaullier at cji.paris>

Add support for variable or unknown 'offset':
- phase change or jitter
- Dolby E D2

Fix sync in several cases:
- Dolby E integer rounded sample_rate
- Missing frames (replaced by silence)

Signed-off-by: Nicolas Gaullier <nicolas.gaullier at cji.paris>
---
 libavformat/Makefile       |   3 +-
 libavformat/allformats.c   |   3 +-
 libavformat/s337m.c        | 216 +++++++++++--------------------------
 tests/fate/audio.mak       |   5 +-
 tests/fate/demux.mak       |   2 +-
 tests/ref/fate/s337m-demux |  56 +++++-----
 6 files changed, 99 insertions(+), 186 deletions(-)

diff --git a/libavformat/Makefile b/libavformat/Makefile
index 52aa64d43b..9caf205b61 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -531,7 +531,8 @@ OBJS-$(CONFIG_RTSP_DEMUXER)              += rtsp.o rtspdec.o httpauth.o \
                                             urldecode.o
 OBJS-$(CONFIG_RTSP_MUXER)                += rtsp.o rtspenc.o httpauth.o \
                                             urldecode.o
-OBJS-$(CONFIG_S337M_DEMUXER)             += s337m.o
+OBJS-$(CONFIG_S337M_16_DEMUXER)          += s337m.o rawdec.o
+OBJS-$(CONFIG_S337M_24_DEMUXER)          += s337m.o rawdec.o
 OBJS-$(CONFIG_SAMI_DEMUXER)              += samidec.o subtitles.o
 OBJS-$(CONFIG_SAP_DEMUXER)               += sapdec.o
 OBJS-$(CONFIG_SAP_MUXER)                 += sapenc.o
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index 445f13f42a..b16c93a80f 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -413,7 +413,8 @@ extern const FFOutputFormat ff_rtp_muxer;
 extern const FFOutputFormat ff_rtp_mpegts_muxer;
 extern const FFInputFormat  ff_rtsp_demuxer;
 extern const FFOutputFormat ff_rtsp_muxer;
-extern const FFInputFormat  ff_s337m_demuxer;
+extern const FFInputFormat  ff_s337m_16_demuxer;
+extern const FFInputFormat  ff_s337m_24_demuxer;
 extern const FFInputFormat  ff_sami_demuxer;
 extern const FFInputFormat  ff_sap_demuxer;
 extern const FFOutputFormat ff_sap_muxer;
diff --git a/libavformat/s337m.c b/libavformat/s337m.c
index feb0f66cb3..16733bc095 100644
--- a/libavformat/s337m.c
+++ b/libavformat/s337m.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 foo86
+ * S337M demuxer
  *
  * This file is part of FFmpeg.
  *
@@ -18,182 +18,92 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-#include "libavutil/intreadwrite.h"
+#include "libavutil/mem.h"
+#include "libavcodec/codec_id.h"
 #include "libavcodec/spdif_s337m_parser_internal.h"
+
 #include "avformat.h"
-#include "demux.h"
 #include "internal.h"
-#include "spdif.h"
-
-#define MARKER_16LE         0x72F81F4E
-#define MARKER_20LE         0x20876FF0E154
-#define MARKER_24LE         0x72F8961F4EA5
-
-#define IS_16LE_MARKER(state)   ((state & 0xFFFFFFFF) == MARKER_16LE)
-#define IS_20LE_MARKER(state)   ((state & 0xF0FFFFF0FFFF) == MARKER_20LE)
-#define IS_24LE_MARKER(state)   ((state & 0xFFFFFFFFFFFF) == MARKER_24LE)
-#define IS_LE_MARKER(state)     (IS_16LE_MARKER(state) || IS_20LE_MARKER(state) || IS_24LE_MARKER(state))
-
-static int s337m_get_offset_and_codec(void *avc,
-                                      uint64_t state,
-                                      int data_type, int data_size,
-                                      int *offset, enum AVCodecID *codec)
-{
-    int word_bits;
-
-    if (IS_16LE_MARKER(state)) {
-        word_bits = 16;
-    } else if (IS_20LE_MARKER(state)) {
-        data_type >>= 8;
-        data_size >>= 4;
-        word_bits = 20;
-    } else {
-        data_type >>= 8;
-        word_bits = 24;
-    }
-
-    if ((data_type & 0x1F) != 0x1C) {
-        if (avc)
-            avpriv_report_missing_feature(avc, "Data type %#x in SMPTE 337M", data_type & 0x1F);
-        return AVERROR_PATCHWELCOME;
-    }
-
-    if (codec)
-        *codec = AV_CODEC_ID_DOLBY_E;
+#include "rawdec.h"
 
-    switch (data_size / word_bits) {
-    case 3648:
-        *offset = 1920;
-        break;
-    case 3644:
-        *offset = 2002;
-        break;
-    case 3640:
-        *offset = 2000;
-        break;
-    case 3040:
-        *offset = 1601;
-        break;
-    default:
-        if (avc)
-            avpriv_report_missing_feature(avc, "Dolby E data size %d in SMPTE 337M", data_size);
-        return AVERROR_PATCHWELCOME;
-    }
+#define AES_DEFAULT_RATE 48000
+#define MAX_FRAME_RATE 30
+#define PROBE_MIN_FRAMES 2
 
-    *offset -= 4;
-    *offset *= (word_bits + 7 >> 3) * 2;
-    return 0;
-}
-
-static int s337m_probe(const AVProbeData *p)
+static int s337m_probe(const AVProbeData *p, int aes_word_bits)
 {
-    uint64_t state = 0;
-    int markers[3] = { 0 };
-    int i, pos, sum, max, data_type, data_size, offset;
-    uint8_t *buf;
-
-    for (pos = 0; pos < p->buf_size; pos++) {
-        state = (state << 8) | p->buf[pos];
-        if (!IS_LE_MARKER(state))
-            continue;
-
-        buf = p->buf + pos + 1;
-        if (IS_16LE_MARKER(state)) {
-            data_type = AV_RL16(buf    );
-            data_size = AV_RL16(buf + 2);
-        } else {
-            data_type = AV_RL24(buf    );
-            data_size = AV_RL24(buf + 3);
+    SPDIFS337MParseContext *pc1;
+    int count_sync = 0, pos = 0;
+
+    if (p->buf_size / (aes_word_bits >> 2) < PROBE_MIN_FRAMES * AES_DEFAULT_RATE / MAX_FRAME_RATE)
+        return 0;
+    pc1 = av_mallocz(sizeof(*pc1));
+    if (!pc1)
+        return AVERROR(ENOMEM);
+    while(pos < p->buf_size) {
+        int next;
+
+        next = avpriv_spdif_s337m_find_syncword(pc1, p->buf + pos, p->buf_size - pos, aes_word_bits);
+        if (next == END_NOT_FOUND)
+            goto not_found;
+        pos += next;
+        next = avpriv_s337m_parse_header(NULL, p->buf + pos, p->buf_size - pos, aes_word_bits);
+        if (next > 0 && ++count_sync >= PROBE_MIN_FRAMES) {
+            av_free(pc1);
+            return AVPROBE_SCORE_EXTENSION + 1;
         }
-
-        if (s337m_get_offset_and_codec(NULL, state, data_type, data_size, &offset, NULL))
-            continue;
-
-        i = IS_16LE_MARKER(state) ? 0 : IS_20LE_MARKER(state) ? 1 : 2;
-        markers[i]++;
-
-        pos  += IS_16LE_MARKER(state) ? 4 : 6;
-        pos  += offset;
-        state = 0;
     }
 
-    sum = max = 0;
-    for (i = 0; i < FF_ARRAY_ELEMS(markers); i++) {
-        sum += markers[i];
-        if (markers[max] < markers[i])
-            max = i;
-    }
-
-    if (markers[max] > 3 && markers[max] * 4 > sum * 3)
-        return AVPROBE_SCORE_EXTENSION + 1;
-
+not_found:
+    av_free(pc1);
     return 0;
 }
 
-static int s337m_read_header(AVFormatContext *s)
+static int s337m_probe_16(const AVProbeData *p)
 {
-    s->ctx_flags |= AVFMTCTX_NOHEADER;
-    return 0;
+    return s337m_probe(p, 16);
 }
-
-static void bswap_buf24(uint8_t *data, int size)
+static int s337m_probe_24(const AVProbeData *p)
 {
-    int i;
-
-    for (i = 0; i < size / 3; i++, data += 3)
-        FFSWAP(uint8_t, data[0], data[2]);
+    return s337m_probe(p, 24);
 }
 
-static int s337m_read_packet(AVFormatContext *s, AVPacket *pkt)
+static int s337m_read_header(AVFormatContext *s)
 {
-    AVIOContext *pb = s->pb;
-    uint64_t state = 0;
-    int ret, data_type, data_size, offset;
-    enum AVCodecID codec;
+    AVCodecParameters *par;
+    AVStream *st;
+    int ret = ff_raw_audio_read_header(s);
 
-    while (!IS_LE_MARKER(state)) {
-        state = (state << 8) | avio_r8(pb);
-        if (avio_feof(pb))
-            return AVERROR_EOF;
-    }
-
-    if (IS_16LE_MARKER(state)) {
-        data_type = avio_rl16(pb);
-        data_size = avio_rl16(pb);
-    } else {
-        data_type = avio_rl24(pb);
-        data_size = avio_rl24(pb);
-    }
-
-    if ((ret = s337m_get_offset_and_codec(s, state, data_type, data_size, &offset, &codec)) < 0)
+    if (ret < 0)
         return ret;
+    st = s->streams[0];
+    par = st->codecpar;
+    par->sample_rate = AES_DEFAULT_RATE;
+    par->bits_per_coded_sample = av_get_bits_per_sample(par->codec_id);
 
-    if ((ret = av_get_packet(pb, pkt, offset)) != offset)
-        return ret < 0 ? ret : AVERROR_EOF;
-
-    if (IS_16LE_MARKER(state))
-        avpriv_spdif_s337m_bswap_buf16((uint16_t *)pkt->data, (uint16_t *)pkt->data, pkt->size >> 1);
-    else
-        bswap_buf24(pkt->data, pkt->size);
-
-    if (!s->nb_streams) {
-        AVStream *st = avformat_new_stream(s, NULL);
-        if (!st) {
-            return AVERROR(ENOMEM);
-        }
-        st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
-        st->codecpar->codec_id   = codec;
-        ffstream(st)->need_parsing = AVSTREAM_PARSE_HEADERS;
-    }
-
+    avpriv_set_pts_info(st, 64, 1, par->sample_rate);
     return 0;
 }
 
-const FFInputFormat ff_s337m_demuxer = {
-    .p.name         = "s337m",
-    .p.long_name    = NULL_IF_CONFIG_SMALL("SMPTE 337M"),
+const FFInputFormat ff_s337m_16_demuxer = {
+    .p.name         = "s337m_16",
+    .p.long_name    = NULL_IF_CONFIG_SMALL("SMPTE 337M within 16-bit pcm"),
+    .p.flags        = AVFMT_GENERIC_INDEX,
+    .p.priv_class   = &ff_raw_demuxer_class,
+    .read_probe     = s337m_probe_16,
+    .read_header    = s337m_read_header,
+    .read_packet    = ff_raw_read_partial_packet,
+    .raw_codec_id   = AV_CODEC_ID_S337M_16,
+    .priv_data_size = sizeof(FFRawDemuxerContext),
+};
+const FFInputFormat ff_s337m_24_demuxer = {
+    .p.name         = "s337m_24",
+    .p.long_name    = NULL_IF_CONFIG_SMALL("SMPTE 337M within 24-bit pcm"),
     .p.flags        = AVFMT_GENERIC_INDEX,
-    .read_probe     = s337m_probe,
+    .p.priv_class   = &ff_raw_demuxer_class,
+    .read_probe     = s337m_probe_24,
     .read_header    = s337m_read_header,
-    .read_packet    = s337m_read_packet,
+    .read_packet    = ff_raw_read_partial_packet,
+    .raw_codec_id   = AV_CODEC_ID_S337M_24,
+    .priv_data_size = sizeof(FFRawDemuxerContext),
 };
diff --git a/tests/fate/audio.mak b/tests/fate/audio.mak
index 4d6c479b6b..421c4e12f4 100644
--- a/tests/fate/audio.mak
+++ b/tests/fate/audio.mak
@@ -26,10 +26,11 @@ fate-bmv-audio: CMD = framecrc -i $(TARGET_SAMPLES)/bmv/SURFING-partial.BMV -vn
 FATE_SAMPLES_AUDIO-$(call DEMDEC, DSICIN, DSICINAUDIO) += fate-delphine-cin-audio
 fate-delphine-cin-audio: CMD = framecrc -i $(TARGET_SAMPLES)/delphine-cin/LOGO-partial.CIN -vn
 
-FATE_SAMPLES_AUDIO-$(call DEMDEC, S337M, DOLBY_E, ARESAMPLE_FILTER) += fate-dolby-e
-fate-dolby-e: CMD = pcm -i $(TARGET_SAMPLES)/dolby_e/16-11
+FATE_SAMPLES_AUDIO-$(call PCM, S337M_16, DOLBY_E, ARESAMPLE_FILTER) += fate-dolby-e
+fate-dolby-e: CMD = pcm -i $(TARGET_SAMPLES)/dolby_e/16-11 -ar 44800
 fate-dolby-e: CMP = oneoff
 fate-dolby-e: REF = $(SAMPLES)/dolby_e/16-11.pcm
+fate-dolby-e: FUZZ = 2
 
 FATE_SAMPLES_AUDIO-$(call DEMDEC, DSS, DSS_SP, ARESAMPLE_FILTER) += fate-dss-lp
 fate-dss-lp: CMD = framecrc -i $(TARGET_SAMPLES)/dss/lp.dss -frames 30 -af aresample
diff --git a/tests/fate/demux.mak b/tests/fate/demux.mak
index e0d1fccc8f..f70491f158 100644
--- a/tests/fate/demux.mak
+++ b/tests/fate/demux.mak
@@ -130,7 +130,7 @@ fate-qcp-demux: CMD = crc -i $(TARGET_SAMPLES)/qcp/0036580847.QCP -c:a copy
 FATE_SAMPLES_DEMUX-$(CONFIG_R3D_DEMUXER) += fate-redcode-demux
 fate-redcode-demux: CMD = framecrc -i $(TARGET_SAMPLES)/r3d/4MB-sample.r3d -c:v copy -c:a copy
 
-FATE_SAMPLES_DEMUX-$(call ALLYES, S337M_DEMUXER DOLBY_E_PARSER FRAMECRC_MUXER) += fate-s337m-demux
+FATE_SAMPLES_DEMUX-$(call FRAMECRC, S337M_16,, S337M_16_PARSER FRAMECRC_MUXER) += fate-s337m-demux
 fate-s337m-demux: CMD = framecrc -i $(TARGET_SAMPLES)/dolby_e/16-11 -c copy -ss 2 -t 1
 
 FATE_SAMPLES_DEMUX-$(CONFIG_SIFF_DEMUXER) += fate-siff-demux
diff --git a/tests/ref/fate/s337m-demux b/tests/ref/fate/s337m-demux
index 42ef4df275..35a7a58d49 100644
--- a/tests/ref/fate/s337m-demux
+++ b/tests/ref/fate/s337m-demux
@@ -1,30 +1,30 @@
-#tb 0: 1/90000
+#tb 0: 1/48000
 #media_type 0: audio
-#codec_id 0: dolby_e
-#sample_rate 0: 44800
+#codec_id 0: s337m_16
+#sample_rate 0: 48000
 #channel_layout_name 0: 5.1(side)
-0,          0,          0,     3600,     7664, 0x7e73f2fd
-0,       3600,       3600,     3600,     7664, 0x8b980ec8
-0,       7200,       7200,     3600,     7664, 0xa16adbd5
-0,      10800,      10800,     3600,     7664, 0x6d1b43a5
-0,      14400,      14400,     3600,     7664, 0xb7e52e2a
-0,      18000,      18000,     3600,     7664, 0xcb7d6463
-0,      21600,      21600,     3600,     7664, 0x148a557b
-0,      25200,      25200,     3600,     7664, 0x04c0142e
-0,      28800,      28800,     3600,     7664, 0xf96de1d4
-0,      32400,      32400,     3600,     7664, 0x9f3224e0
-0,      36000,      36000,     3600,     7664, 0x6bd905cb
-0,      39600,      39600,     3600,     7664, 0xe6782023
-0,      43200,      43200,     3600,     7664, 0x983f5048
-0,      46800,      46800,     3600,     7664, 0x017df49a
-0,      50400,      50400,     3600,     7664, 0x25e605a9
-0,      54000,      54000,     3600,     7664, 0x764ef01e
-0,      57600,      57600,     3600,     7664, 0x3830f9f0
-0,      61200,      61200,     3600,     7664, 0xbcd62352
-0,      64800,      64800,     3600,     7664, 0x51ab1a35
-0,      68400,      68400,     3600,     7664, 0xc21ff964
-0,      72000,      72000,     3600,     7664, 0x9d6c0efa
-0,      75600,      75600,     3600,     7664, 0x5e55dd80
-0,      79200,      79200,     3600,     7664, 0xfd9eeb6d
-0,      82800,      82800,     3600,     7664, 0xcf86ce9d
-0,      86400,      86400,     3600,     7664, 0xc6e8319c
+0,        345,        345,     1920,     7680, 0x4df0f5d4
+0,       2265,       2265,     1920,     7680, 0x420e119f
+0,       4185,       4185,     1920,     7680, 0x09dfdeac
+0,       6105,       6105,     1920,     7680, 0xd9e3467c
+0,       8025,       8025,     1920,     7680, 0x8ec43101
+0,       9945,       9945,     1920,     7680, 0x955d673a
+0,      11865,      11865,     1920,     7680, 0x2fa95852
+0,      13785,      13785,     1920,     7680, 0x299e1705
+0,      15705,      15705,     1920,     7680, 0x35c1e4ab
+0,      17625,      17625,     1920,     7680, 0x5ae127b7
+0,      19545,      19545,     1920,     7680, 0xe52108a2
+0,      21465,      21465,     1920,     7680, 0x3e5c22fa
+0,      23385,      23385,     1920,     7680, 0x89c1531f
+0,      25305,      25305,     1920,     7680, 0xeb56f771
+0,      27225,      27225,     1920,     7680, 0xae960880
+0,      29145,      29145,     1920,     7680, 0x307ef2f5
+0,      31065,      31065,     1920,     7680, 0x4d54fcc7
+0,      32985,      32985,     1920,     7680, 0x29732629
+0,      34905,      34905,     1920,     7680, 0x57481d0c
+0,      36825,      36825,     1920,     7680, 0xdc91fc3b
+0,      38745,      38745,     1920,     7680, 0x9c4e11d1
+0,      40665,      40665,     1920,     7680, 0x829ce057
+0,      42585,      42585,     1920,     7680, 0xb145ee44
+0,      44505,      44505,     1920,     7680, 0x798ed174
+0,      46425,      46425,     1920,     7680, 0x091c3473
-- 
2.30.2



More information about the ffmpeg-devel mailing list