From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <ffmpeg-devel-bounces@ffmpeg.org>
Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100])
	by master.gitmailbox.com (Postfix) with ESMTPS id D6E034D976
	for <ffmpegdev@gitmailbox.com>; Mon, 21 Apr 2025 15:25:36 +0000 (UTC)
Received: from [127.0.1.1] (localhost [127.0.0.1])
	by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 84E98687EB0;
	Mon, 21 Apr 2025 18:25:02 +0300 (EEST)
Received: from mail-wr1-f43.google.com (mail-wr1-f43.google.com
 [209.85.221.43])
 by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id C514E687DBB
 for <ffmpeg-devel@ffmpeg.org>; Mon, 21 Apr 2025 18:24:52 +0300 (EEST)
Received: by mail-wr1-f43.google.com with SMTP id
 ffacd0b85a97d-39ee5ac4321so4345892f8f.1
 for <ffmpeg-devel@ffmpeg.org>; Mon, 21 Apr 2025 08:24:52 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=jkqxz-net.20230601.gappssmtp.com; s=20230601; t=1745249092; x=1745853892;
 darn=ffmpeg.org; 
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:to:from:from:to:cc:subject:date:message-id
 :reply-to; bh=31zIGRtpVOyKoHeU9rXCLuOCwVoPzb/ltO1YJaJqtS8=;
 b=qf92m/sQdWwcVZmVCwdlQtn4/qMlfVliXaFjdHtGSvMmhw7ZiU12WsmxRQc3rnb8ZJ
 /0MJsrrhAplVtDeOyQF3ETwuEneTFxbguD43vn0toSmW+5b9DYEH1AGM4YleMWYgJiWQ
 bBAiv/lSAzLLkt/Q3qnx43C4VJB0pR+1OSuLPVv5XXRoo4Psh0WecjpnM2nkShryyKS2
 BfDWRtHiadvwjOX2kjh3FGnMVySJOf4Nt+2R+BA/ZA0DbJO/Bc5IFPGMStUxKis2tr+v
 6SsDAkrVFdzxIgnsbdzt6y0ludeG5JUEDp6eFy06FaVwOJPzIdiItwKe4zDyDke3/vhv
 7vQA==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1745249092; x=1745853892;
 h=content-transfer-encoding:mime-version:references:in-reply-to
 :message-id:date:subject:to:from:x-gm-message-state:from:to:cc
 :subject:date:message-id:reply-to;
 bh=31zIGRtpVOyKoHeU9rXCLuOCwVoPzb/ltO1YJaJqtS8=;
 b=tmfUkD8OnK2WZgZmQizVJByVxJR91rsZSmUAKinG2avHWdXSbJHlB1MnW/4DKaDMfo
 e3h5OR8lsTlU5+4P+cWb9e6iOxoztu+eyY7o0J4FqUQWxXg6BVHWe4K55PU5CNw34XNO
 BNxx23vJaQG9qqrL9h9OUt35vtjjFdpys+W0QmkvZHf883CQp8BDHwaQ5NflUM3Gbu+5
 nLGg1oRp4BKscam4bBcSl5GOvg1fSqratJbcKOMHYEx7T+RflZDT5ZdZypByGAcK/aVm
 SFkSohgUAzXY24H8u3wcKjI4WSQQCENbDRGuJJaEYn1mF4ulnNqRsQgrqTBHfgTQdkF9
 Cn9Q==
X-Gm-Message-State: AOJu0YygHtonaHg3vcfMuGVwdWaSq/NJgzyc1wB6CQXSR2n/kGCqBO/U
 vNrNQcMoX2DEOl5XYNtr3bGJk8sD42UYo9ULHo5uSE/cpBqFfcaaVcFRCnY95mSsF2thwepTnPU
 l
X-Gm-Gg: ASbGnctfROzt2OXgUAOqLkxeUlRXlIiDPd8IpYEhXX5lCQg4xm8eun4UfIVIXGqZX+v
 ig5PDueIeyO+C07NunlAvR/NVTfbVpKdebNvEDYtRs3YXQn1LvHAYpRs16KqfOpF09FKGZRGnpH
 YL6i3HG8O8DsDdffyusoJFAfW8dUoMsPPQjxeEsfaPPLYjU3rqFAN1HGRyDVy7+O6XpYU77egZi
 HchS52v5TIuTY7nOcoq6y2E1WXmtqOf/YlFf9eDQLPGR+L2xi9wyZvbuxFO23gQzhaA5h59/KPd
 2U0xgawRRn4SlNQNCZb2U4dj01ZZv+R5RWi7kOhRQ3lBSwgJDOl9Xx6pw7tYKT/LTSbUy2fS4kU
 cdkwHYz6MnYbK4JT6zTHqkx4=
X-Google-Smtp-Source: AGHT+IFpNysMQ0KzqTmlsbNMUShbUK5ADOzrEhNVaJ1QaNCI+5GFSovhE3jAxNLvVWrZL65NtbRrMQ==
X-Received: by 2002:a05:6000:2903:b0:39c:30d9:3b5c with SMTP id
 ffacd0b85a97d-39efbad53f0mr9641285f8f.39.1745249091892; 
 Mon, 21 Apr 2025 08:24:51 -0700 (PDT)
Received: from localhost.localdomain
 (cpc92320-cmbg19-2-0-cust719.5-4.cable.virginm.net. [82.13.66.208])
 by smtp.gmail.com with ESMTPSA id
 5b1f17b1804b1-4406d5bbc07sm140657145e9.17.2025.04.21.08.24.51
 for <ffmpeg-devel@ffmpeg.org>
 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
 Mon, 21 Apr 2025 08:24:51 -0700 (PDT)
From: Mark Thompson <sw@jkqxz.net>
To: ffmpeg-devel@ffmpeg.org
Date: Mon, 21 Apr 2025 16:24:34 +0100
Message-ID: <20250421152445.2110045-4-sw@jkqxz.net>
X-Mailer: git-send-email 2.47.2
In-Reply-To: <20250421152445.2110045-1-sw@jkqxz.net>
References: <20250421152445.2110045-1-sw@jkqxz.net>
MIME-Version: 1.0
Subject: [FFmpeg-devel] [PATCH v2 3/6] lavf: APV demuxer
X-BeenThere: ffmpeg-devel@ffmpeg.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: FFmpeg development discussions and patches <ffmpeg-devel.ffmpeg.org>
List-Unsubscribe: <https://ffmpeg.org/mailman/options/ffmpeg-devel>,
 <mailto:ffmpeg-devel-request@ffmpeg.org?subject=unsubscribe>
List-Archive: <https://ffmpeg.org/pipermail/ffmpeg-devel>
List-Post: <mailto:ffmpeg-devel@ffmpeg.org>
List-Help: <mailto:ffmpeg-devel-request@ffmpeg.org?subject=help>
List-Subscribe: <https://ffmpeg.org/mailman/listinfo/ffmpeg-devel>,
 <mailto:ffmpeg-devel-request@ffmpeg.org?subject=subscribe>
Reply-To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org>
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit
Errors-To: ffmpeg-devel-bounces@ffmpeg.org
Sender: "ffmpeg-devel" <ffmpeg-devel-bounces@ffmpeg.org>
Archived-At: <https://master.gitmailbox.com/ffmpegdev/20250421152445.2110045-4-sw@jkqxz.net/>
List-Archive: <https://master.gitmailbox.com/ffmpegdev/>
List-Post: <mailto:ffmpegdev@gitmailbox.com>

Demuxes raw streams as defined in draft spec section 10.2.
---
 libavformat/Makefile     |   1 +
 libavformat/allformats.c |   1 +
 libavformat/apvdec.c     | 248 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 250 insertions(+)
 create mode 100644 libavformat/apvdec.c

diff --git a/libavformat/Makefile b/libavformat/Makefile
index a94ac66e7e..ef96c2762e 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -119,6 +119,7 @@ OBJS-$(CONFIG_APTX_DEMUXER)              += aptxdec.o
 OBJS-$(CONFIG_APTX_MUXER)                += rawenc.o
 OBJS-$(CONFIG_APTX_HD_DEMUXER)           += aptxdec.o
 OBJS-$(CONFIG_APTX_HD_MUXER)             += rawenc.o
+OBJS-$(CONFIG_APV_DEMUXER)               += apvdec.o
 OBJS-$(CONFIG_AQTITLE_DEMUXER)           += aqtitledec.o subtitles.o
 OBJS-$(CONFIG_ARGO_ASF_DEMUXER)          += argo_asf.o
 OBJS-$(CONFIG_ARGO_ASF_MUXER)            += argo_asf.o
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index 445f13f42a..90a4fe64ec 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -72,6 +72,7 @@ extern const FFInputFormat  ff_aptx_demuxer;
 extern const FFOutputFormat ff_aptx_muxer;
 extern const FFInputFormat  ff_aptx_hd_demuxer;
 extern const FFOutputFormat ff_aptx_hd_muxer;
+extern const FFInputFormat  ff_apv_demuxer;
 extern const FFInputFormat  ff_aqtitle_demuxer;
 extern const FFInputFormat  ff_argo_asf_demuxer;
 extern const FFOutputFormat ff_argo_asf_muxer;
diff --git a/libavformat/apvdec.c b/libavformat/apvdec.c
new file mode 100644
index 0000000000..f2e6982e48
--- /dev/null
+++ b/libavformat/apvdec.c
@@ -0,0 +1,248 @@
+/*
+ * 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 "libavcodec/apv.h"
+#include "libavcodec/get_bits.h"
+#include "avformat.h"
+#include "avio_internal.h"
+#include "demux.h"
+#include "internal.h"
+
+
+#define APV_TAG MKBETAG('a', 'P', 'v', '1')
+
+typedef struct APVHeaderInfo {
+    uint8_t  pbu_type;
+    uint16_t group_id;
+
+    uint8_t  profile_idc;
+    uint8_t  level_idc;
+    uint8_t  band_idc;
+
+    int      frame_width;
+    int      frame_height;
+
+    uint8_t  chroma_format_idc;
+    uint8_t  bit_depth_minus8;
+
+    enum AVPixelFormat pixel_format;
+} APVHeaderInfo;
+
+static const enum AVPixelFormat apv_format_table[5][5] = {
+    { AV_PIX_FMT_GRAY8,    AV_PIX_FMT_GRAY10,     AV_PIX_FMT_GRAY12,     AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16 },
+    { 0 }, // 4:2:0 is not valid.
+    { AV_PIX_FMT_YUV422P,  AV_PIX_FMT_YUV422P10,  AV_PIX_FMT_YUV422P12,  AV_PIX_FMT_GRAY14, AV_PIX_FMT_YUV422P16 },
+    { AV_PIX_FMT_YUV444P,  AV_PIX_FMT_YUV444P10,  AV_PIX_FMT_YUV444P12,  AV_PIX_FMT_GRAY14, AV_PIX_FMT_YUV444P16 },
+    { AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA444P12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_YUVA444P16 },
+};
+
+static int apv_extract_header_info(APVHeaderInfo *info,
+                                   GetBitContext *gbc)
+{
+    int zero, bit_depth_index;
+
+    info->pbu_type = get_bits(gbc, 8);
+    info->group_id = get_bits(gbc, 16);
+
+    zero = get_bits(gbc, 8);
+    if (zero != 0)
+        return AVERROR_INVALIDDATA;
+
+    if (info->pbu_type != APV_PBU_PRIMARY_FRAME)
+        return AVERROR_INVALIDDATA;
+
+    info->profile_idc = get_bits(gbc, 8);
+    info->level_idc   = get_bits(gbc, 8);
+    info->band_idc    = get_bits(gbc, 3);
+
+    zero = get_bits(gbc, 5);
+    if (zero != 0)
+        return AVERROR_INVALIDDATA;
+
+    info->frame_width  = get_bits(gbc, 24);
+    info->frame_height = get_bits(gbc, 24);
+    if (info->frame_width  < 1 || info->frame_width  > 65536 ||
+        info->frame_height < 1 || info->frame_height > 65536)
+        return AVERROR_INVALIDDATA;
+
+    info->chroma_format_idc = get_bits(gbc, 4);
+    info->bit_depth_minus8  = get_bits(gbc, 4);
+
+    if (info->bit_depth_minus8 > 8) {
+        return AVERROR_INVALIDDATA;
+    }
+    if (info->bit_depth_minus8 % 2) {
+        // Odd bit depths are technically valid but not useful here.
+        return AVERROR_INVALIDDATA;
+    }
+    bit_depth_index = info->bit_depth_minus8 / 2;
+
+    switch (info->chroma_format_idc) {
+    case APV_CHROMA_FORMAT_400:
+    case APV_CHROMA_FORMAT_422:
+    case APV_CHROMA_FORMAT_444:
+    case APV_CHROMA_FORMAT_4444:
+        info->pixel_format = apv_format_table[info->chroma_format_idc][bit_depth_index];
+        break;
+    default:
+        return AVERROR_INVALIDDATA;
+    }
+
+    // Ignore capture_time_distance.
+    skip_bits(gbc, 8);
+
+    zero = get_bits(gbc, 8);
+    if (zero != 0)
+        return AVERROR_INVALIDDATA;
+
+    return 1;
+}
+
+static int apv_probe(const AVProbeData *p)
+{
+    GetBitContext gbc;
+    APVHeaderInfo header;
+    uint32_t au_size, tag, pbu_size;
+    int score = AVPROBE_SCORE_EXTENSION + 1;
+    int err;
+
+    init_get_bits8(&gbc, p->buf, p->buf_size);
+
+    au_size = get_bits_long(&gbc, 32);
+    if (au_size < 16) {
+        // Too small.
+        return 0;
+    }
+    // The spec doesn't have this tag, but the reference software and
+    // all current files do.  Treat it as optional and skip if present,
+    // but if it is there then this is definitely an APV file.
+    tag = get_bits_long(&gbc, 32);
+    if (tag == APV_TAG) {
+        pbu_size = get_bits_long(&gbc, 32);
+        score = AVPROBE_SCORE_MAX;
+    } else {
+        pbu_size = tag;
+    }
+    if (pbu_size < 16) {
+        // Too small.
+        return 0;
+    }
+
+    err = apv_extract_header_info(&header, &gbc);
+    if (err < 0) {
+        // Header does not look like APV.
+        return 0;
+    }
+    return score;
+}
+
+static int apv_read_header(AVFormatContext *s)
+{
+    AVStream *st;
+    GetBitContext gbc;
+    APVHeaderInfo header;
+    uint8_t buffer[32];
+    uint32_t au_size, tag, pbu_size;
+    int err, size;
+
+    err = ffio_ensure_seekback(s->pb, sizeof(buffer));
+    if (err < 0)
+        return err;
+    size = avio_read(s->pb, buffer, sizeof(buffer));
+    if (size < 0)
+        return size;
+
+    init_get_bits8(&gbc, buffer, sizeof(buffer));
+
+    au_size = get_bits_long(&gbc, 32);
+    if (au_size < 16) {
+        // Too small.
+        return AVERROR_INVALIDDATA;
+    }
+    tag = get_bits_long(&gbc, 32);
+    if (tag == APV_TAG) {
+        pbu_size = get_bits_long(&gbc, 32);
+    } else {
+        pbu_size = tag;
+    }
+    if (pbu_size < 16) {
+        // Too small.
+        return AVERROR_INVALIDDATA;
+    }
+
+    err = apv_extract_header_info(&header, &gbc);
+    if (err < 0)
+        return err;
+
+    st = avformat_new_stream(s, NULL);
+    if (!st)
+        return AVERROR(ENOMEM);
+
+    st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
+    st->codecpar->codec_id   = AV_CODEC_ID_APV;
+    st->codecpar->format     = header.pixel_format;
+    st->codecpar->profile    = header.profile_idc;
+    st->codecpar->level      = header.level_idc;
+    st->codecpar->width      = header.frame_width;
+    st->codecpar->height     = header.frame_height;
+
+    st->avg_frame_rate = (AVRational){ 30, 1 };
+    avpriv_set_pts_info(st, 64, 1, 30);
+
+    avio_seek(s->pb, -size, SEEK_CUR);
+
+    return 0;
+}
+
+static int apv_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+    uint32_t au_size, tag;
+    int ret;
+
+    au_size = avio_rb32(s->pb);
+    if (au_size == 0 && avio_feof(s->pb))
+        return AVERROR_EOF;
+
+    tag = avio_rb32(s->pb);
+    if (tag == APV_TAG) {
+        au_size -= 4;
+    } else {
+        avio_seek(s->pb, -4, SEEK_CUR);
+    }
+
+    if (au_size < 16 || au_size > 1 << 24) {
+        av_log(s, AV_LOG_ERROR, "APV AU is bad\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    ret = av_get_packet(s->pb, pkt, au_size);
+    pkt->flags        = AV_PKT_FLAG_KEY;
+
+    return ret;
+}
+
+const FFInputFormat ff_apv_demuxer = {
+    .p.name         = "apv",
+    .p.long_name    = NULL_IF_CONFIG_SMALL("APV raw bitstream"),
+    .p.extensions   = "apv",
+    .p.flags        = AVFMT_GENERIC_INDEX | AVFMT_NOTIMESTAMPS,
+    .flags_internal = FF_INFMT_FLAG_INIT_CLEANUP,
+    .read_probe     = apv_probe,
+    .read_header    = apv_read_header,
+    .read_packet    = apv_read_packet,
+};
-- 
2.47.2

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".