[FFmpeg-devel] [PATCH 5/7] avformat/mpegts: add s337m support
ffnicolasg at sfr.fr
ffnicolasg at sfr.fr
Wed Dec 4 16:14:07 EET 2024
From: Nicolas Gaullier <nicolas.gaullier at cji.paris>
Move s302m decoder from avcodec to avformat.
Set AVSTREAM_PARSE_FULL for s337m support.
Signed-off-by: Nicolas Gaullier <nicolas.gaullier at cji.paris>
---
libavformat/mpegts.c | 138 +++++++++++++++++++++++++++++++++++++++++-
tests/fate/acodec.mak | 3 +-
2 files changed, 139 insertions(+), 2 deletions(-)
diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
index 177e610e53..fd649751fc 100644
--- a/libavformat/mpegts.c
+++ b/libavformat/mpegts.c
@@ -31,6 +31,7 @@
#include "libavutil/opt.h"
#include "libavutil/avassert.h"
#include "libavutil/dovi_meta.h"
+#include "libavutil/reverse.h"
#include "libavcodec/bytestream.h"
#include "libavcodec/defs.h"
#include "libavcodec/get_bits.h"
@@ -1009,6 +1010,125 @@ static void new_data_packet(const uint8_t *buffer, int len, AVPacket *pkt)
pkt->size = len;
}
+#define AES3_HEADER_LEN 4
+static int s302m_parse_frame_header(void *avc, AVCodecParameters *par, const uint8_t *buf,
+ int buf_size)
+{
+ uint32_t h;
+ int frame_size, channels, bits;
+
+ if (buf_size <= AES3_HEADER_LEN) {
+ av_log(avc, AV_LOG_ERROR, "frame is too short\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ /*
+ * AES3 header :
+ * size: 16
+ * number channels 2
+ * channel_id 8
+ * bits per samples 2
+ * alignments 4
+ */
+
+ h = AV_RB32(buf);
+ frame_size = (h >> 16) & 0xffff;
+ channels = ((h >> 14) & 0x0003) * 2 + 2;
+ bits = ((h >> 4) & 0x0003) * 4 + 16;
+
+ if (bits > 24) {
+ av_log(avc, AV_LOG_ERROR, "frame has invalid header\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ /* Output properties may have been overriden by stream probing after
+ * avformat_find_stream_info and must be preserved */
+ if (par->codec_id != AV_CODEC_ID_S302M
+ && par->codec_id != AV_CODEC_ID_PCM_S24LE
+ && par->codec_id != AV_CODEC_ID_PCM_S16LE)
+ goto end;
+
+ /* Set output properties */
+ par->bits_per_raw_sample = bits;
+ if (bits > 16)
+ par->codec_id = AV_CODEC_ID_PCM_S24LE;
+ else
+ par->codec_id = AV_CODEC_ID_PCM_S16LE;
+
+ av_channel_layout_uninit(&par->ch_layout);
+ switch(channels) {
+ case 2:
+ par->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO;
+ break;
+ case 4:
+ par->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_QUAD;
+ break;
+ case 6:
+ par->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_5POINT1_BACK;
+ break;
+ case 8:
+ av_channel_layout_from_mask(&par->ch_layout,
+ AV_CH_LAYOUT_5POINT1_BACK | AV_CH_LAYOUT_STEREO_DOWNMIX);
+ break;
+ default:
+ par->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC;
+ par->ch_layout.nb_channels = channels;
+ break;
+ }
+
+ par->sample_rate = 48000;
+
+end:
+ return AES3_HEADER_LEN + frame_size;
+}
+
+static int s302m_demux(AVCodecParameters *par, AVPacket *pkt)
+{
+ int ret = av_packet_make_writable(pkt);
+ if (ret < 0)
+ return ret;
+ pkt->data += AES3_HEADER_LEN;
+ av_shrink_packet(pkt, pkt->size - AES3_HEADER_LEN);
+
+ if (par->bits_per_raw_sample == 24) {
+ uint8_t *buf = pkt->data;
+ uint8_t *buf_out = buf;
+ for (; buf + 6 < pkt->data + pkt->size; buf+=7, buf_out+=6)
+ AV_WL48(buf_out,
+ ((uint64_t)ff_reverse[buf[2]] << 16) |
+ ((uint64_t)ff_reverse[buf[1]] << 8) |
+ ((uint64_t)ff_reverse[buf[0]]) |
+ ((uint64_t)ff_reverse[buf[6] & 0xf0] << 44) |
+ ((uint64_t)ff_reverse[buf[5]] << 36) |
+ ((uint64_t)ff_reverse[buf[4]] << 28) |
+ ((uint64_t)ff_reverse[buf[3] & 0x0f] << 20));
+ av_shrink_packet(pkt, buf_out - pkt->data);
+ }
+ else if (par->bits_per_raw_sample == 20) {
+ uint8_t *buf = pkt->data;
+ for (; buf + 5 < pkt->data + pkt->size; buf+=6)
+ AV_WL48(buf,
+ ((uint64_t)ff_reverse[buf[2] & 0xf0] << 20) |
+ ((uint64_t)ff_reverse[buf[1]] << 12) |
+ ((uint64_t)ff_reverse[buf[0]] << 4) |
+ ((uint64_t)ff_reverse[buf[5] & 0xf0] << 44) |
+ ((uint64_t)ff_reverse[buf[4]] << 36) |
+ ((uint64_t)ff_reverse[buf[3]] << 28));
+ } else {
+ uint8_t *buf = pkt->data;
+ uint8_t *buf_out = buf;
+ for (; buf + 4 < pkt->data + pkt->size; buf+=5, buf_out+=4)
+ AV_WL32(buf_out,
+ ((uint32_t)ff_reverse[buf[1]] << 8) |
+ ((uint32_t)ff_reverse[buf[0]]) |
+ ((uint32_t)ff_reverse[buf[4] & 0xf0] << 28) |
+ ((uint32_t)ff_reverse[buf[3]] << 20) |
+ ((uint32_t)ff_reverse[buf[2] & 0x0f] << 12));
+ av_shrink_packet(pkt, buf_out - pkt->data);
+ }
+ return 0;
+}
+
static int new_pes_packet(PESContext *pes, AVPacket *pkt)
{
uint8_t *sd;
@@ -1032,6 +1152,20 @@ static int new_pes_packet(PESContext *pes, AVPacket *pkt)
pkt->stream_index = pes->sub_st->index;
else
pkt->stream_index = pes->st->index;
+
+ if (pes->st->codecpar->codec_tag == MKTAG('B', 'S', 'S', 'D')) {
+ AVCodecParameters *par = pes->st->codecpar;
+ int expected_buf_size = s302m_parse_frame_header(pes->stream, par, pkt->data, pkt->size);
+
+ if (expected_buf_size != pkt->size)
+ pes->flags |= AV_PKT_FLAG_CORRUPT;
+ if (expected_buf_size > 0) {
+ int ret = s302m_demux(par, pkt);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
pkt->pts = pes->pts;
pkt->dts = pes->dts;
/* store position of first TS packet of this PES packet */
@@ -2024,8 +2158,10 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type
av_log(fc, AV_LOG_TRACE, "reg_desc=%.4s\n", (char *)&st->codecpar->codec_tag);
if (st->codecpar->codec_id == AV_CODEC_ID_NONE || sti->request_probe > 0) {
mpegts_find_stream_type(st, st->codecpar->codec_tag, REGD_types);
- if (st->codecpar->codec_tag == MKTAG('B', 'S', 'S', 'D'))
+ if (st->codecpar->codec_tag == MKTAG('B', 'S', 'S', 'D')) {
sti->request_probe = 50;
+ sti->need_parsing = AVSTREAM_PARSE_FULL;
+ }
}
break;
case 0x52: /* stream identifier descriptor */
diff --git a/tests/fate/acodec.mak b/tests/fate/acodec.mak
index 5bdb89250f..f2def432be 100644
--- a/tests/fate/acodec.mak
+++ b/tests/fate/acodec.mak
@@ -159,7 +159,8 @@ fate-acodec-roqaudio: CODEC = roq_dpcm
fate-acodec-roqaudio: ENCOPTS = -af aresample=22050:tsf=s16p
fate-acodec-roqaudio: DECOPTS = -af aresample=44100:tsf=s16p
-FATE_ACODEC_S302M-$(call ENCDEC, S302M, MPEGTS, ARESAMPLE_FILTER) += 16bit 20bit 24bit
+FATE_ACODEC_S302M-$(call ENCDEC, S302M PCM_S16LE, MPEGTS, ARESAMPLE_FILTER) += 16bit
+FATE_ACODEC_S302M-$(call ENCDEC, S302M PCM_S24LE, MPEGTS, ARESAMPLE_FILTER) += 20bit 24bit
FATE_ACODEC_S302M := $(addprefix fate-acodec-s302m-, $(FATE_ACODEC_S302M-yes))
FATE_ACODEC += $(FATE_ACODEC_S302M)
fate-acodec-s302m: $(FATE_ACODEC_S302M)
--
2.30.2
More information about the ffmpeg-devel
mailing list