* [FFmpeg-devel] [PATCH] Cleanup packet-level BOS/EOS logic. (PR #20640)
@ 2025-10-01 23:02 toots via ffmpeg-devel
0 siblings, 0 replies; only message in thread
From: toots via ffmpeg-devel @ 2025-10-01 23:02 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: toots
PR #20640 opened by toots
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20640
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20640.patch
>From 3a9233d70c02a336a59d85bae753eadc09d86a53 Mon Sep 17 00:00:00 2001
From: Romain Beauxis <romain.beauxis@gmail.com>
Date: Wed, 1 Oct 2025 18:01:13 -0500
Subject: [PATCH] Cleanup packet-level BOS/EOS logic.
---
libavformat/oggdec.c | 6 ++--
libavformat/oggdec.h | 4 +--
libavformat/oggparsecelt.c | 2 +-
libavformat/oggparsedirac.c | 4 +--
libavformat/oggparseflac.c | 6 ++--
libavformat/oggparseogm.c | 6 ++--
libavformat/oggparseopus.c | 36 +++------------------
libavformat/oggparseskeleton.c | 4 +--
libavformat/oggparsespeex.c | 6 ++--
libavformat/oggparsetheora.c | 6 ++--
libavformat/oggparsevorbis.c | 58 ++--------------------------------
libavformat/oggparsevp8.c | 6 ++--
12 files changed, 33 insertions(+), 111 deletions(-)
diff --git a/libavformat/oggdec.c b/libavformat/oggdec.c
index 9f3a92a5ea..2bd2ec1b65 100644
--- a/libavformat/oggdec.c
+++ b/libavformat/oggdec.c
@@ -567,7 +567,8 @@ static int ogg_packet(AVFormatContext *s, int *sid, int *dstart, int *dsize,
os->incomplete = 0;
if (os->header) {
- if ((ret = os->codec->header(s, idx)) < 0) {
+ int is_first = os->flags & OGG_FLAG_BOS && !os->nb_header;
+ if ((ret = os->codec->header(s, idx, is_first)) < 0) {
av_log(s, AV_LOG_ERROR, "Header processing failed: %s\n", av_err2str(ret));
return ret;
}
@@ -605,7 +606,8 @@ static int ogg_packet(AVFormatContext *s, int *sid, int *dstart, int *dsize,
ret = 0;
if (os->codec && os->codec->packet) {
- if ((ret = os->codec->packet(s, idx)) < 0) {
+ int is_last_packet = os->flags & OGG_FLAG_EOS && os->page_end;
+ if ((ret = os->codec->packet(s, idx, is_last_packet)) < 0) {
av_log(s, AV_LOG_ERROR, "Packet processing failed: %s\n", av_err2str(ret));
return ret;
}
diff --git a/libavformat/oggdec.h b/libavformat/oggdec.h
index b051b651e3..76d1c0f0eb 100644
--- a/libavformat/oggdec.h
+++ b/libavformat/oggdec.h
@@ -37,7 +37,7 @@ struct ogg_codec {
* 0 if the packet was not a header (was a data packet)
* -1 if an error occurred or for unsupported stream
*/
- int (*header)(AVFormatContext *, int);
+ int (*header)(AVFormatContext *, int, int);
/**
* Attempt to process a packet as a data packet
* @return < 0 (AVERROR) code or -1 on error
@@ -45,7 +45,7 @@ struct ogg_codec {
* == 1 if the packet was a header from a chained bitstream.
* This will cause the packet to be skipped in calling code (ogg_packet()
*/
- int (*packet)(AVFormatContext *, int);
+ int (*packet)(AVFormatContext *, int, int);
/**
* Translate a granule into a timestamp.
* Will set dts if non-null and known.
diff --git a/libavformat/oggparsecelt.c b/libavformat/oggparsecelt.c
index 626e1ab27d..683e075bf7 100644
--- a/libavformat/oggparsecelt.c
+++ b/libavformat/oggparsecelt.c
@@ -31,7 +31,7 @@ struct oggcelt_private {
int extra_headers_left;
};
-static int celt_header(AVFormatContext *s, int idx)
+static int celt_header(AVFormatContext *s, int idx, int is_first)
{
struct ogg *ogg = s->priv_data;
struct ogg_stream *os = ogg->streams + idx;
diff --git a/libavformat/oggparsedirac.c b/libavformat/oggparsedirac.c
index c5bd43a757..62ded6e592 100644
--- a/libavformat/oggparsedirac.c
+++ b/libavformat/oggparsedirac.c
@@ -26,7 +26,7 @@
#include "internal.h"
#include "oggdec.h"
-static int dirac_header(AVFormatContext *s, int idx)
+static int dirac_header(AVFormatContext *s, int idx, int is_first)
{
struct ogg *ogg = s->priv_data;
struct ogg_stream *os = ogg->streams + idx;
@@ -84,7 +84,7 @@ static uint64_t dirac_gptopts(AVFormatContext *s, int idx, uint64_t granule,
return pts;
}
-static int old_dirac_header(AVFormatContext *s, int idx)
+static int old_dirac_header(AVFormatContext *s, int idx, int is_first)
{
struct ogg *ogg = s->priv_data;
struct ogg_stream *os = ogg->streams + idx;
diff --git a/libavformat/oggparseflac.c b/libavformat/oggparseflac.c
index e81e4021a1..ec68ebb6b8 100644
--- a/libavformat/oggparseflac.c
+++ b/libavformat/oggparseflac.c
@@ -31,7 +31,7 @@
#define OGG_FLAC_MAGIC_SIZE sizeof(OGG_FLAC_MAGIC)-1
static int
-flac_header (AVFormatContext * s, int idx)
+flac_header (AVFormatContext * s, int idx, int is_first)
{
struct ogg *ogg = s->priv_data;
struct ogg_stream *os = ogg->streams + idx;
@@ -81,7 +81,7 @@ flac_header (AVFormatContext * s, int idx)
}
static int
-flac_packet (AVFormatContext * s, int idx)
+flac_packet (AVFormatContext * s, int idx, int is_last)
{
struct ogg *ogg = s->priv_data;
struct ogg_stream *os = ogg->streams + idx;
@@ -109,7 +109,7 @@ flac_packet (AVFormatContext * s, int idx)
}
static int
-old_flac_header (AVFormatContext * s, int idx)
+old_flac_header (AVFormatContext * s, int idx, int is_first)
{
struct ogg *ogg = s->priv_data;
AVStream *st = s->streams[idx];
diff --git a/libavformat/oggparseogm.c b/libavformat/oggparseogm.c
index 1e794745ab..f66db82301 100644
--- a/libavformat/oggparseogm.c
+++ b/libavformat/oggparseogm.c
@@ -34,7 +34,7 @@
#include "riff.h"
static int
-ogm_header(AVFormatContext *s, int idx)
+ogm_header(AVFormatContext *s, int idx, int is_first)
{
struct ogg *ogg = s->priv_data;
struct ogg_stream *os = ogg->streams + idx;
@@ -128,7 +128,7 @@ ogm_header(AVFormatContext *s, int idx)
}
static int
-ogm_dshow_header(AVFormatContext *s, int idx)
+ogm_dshow_header(AVFormatContext *s, int idx, int is_first)
{
struct ogg *ogg = s->priv_data;
struct ogg_stream *os = ogg->streams + idx;
@@ -169,7 +169,7 @@ ogm_dshow_header(AVFormatContext *s, int idx)
}
static int
-ogm_packet(AVFormatContext *s, int idx)
+ogm_packet(AVFormatContext *s, int idx, int is_last)
{
struct ogg *ogg = s->priv_data;
struct ogg_stream *os = ogg->streams + idx;
diff --git a/libavformat/oggparseopus.c b/libavformat/oggparseopus.c
index ae4ff22c53..af1f3e4ba6 100644
--- a/libavformat/oggparseopus.c
+++ b/libavformat/oggparseopus.c
@@ -81,7 +81,7 @@ static int parse_opus_header(AVFormatContext *avf, AVStream *st, struct ogg_stre
return 1;
}
-static int opus_header(AVFormatContext *avf, int idx)
+static int opus_header(AVFormatContext *avf, int idx, int is_first)
{
struct ogg *ogg = avf->priv_data;
struct ogg_stream *os = &ogg->streams[idx];
@@ -95,7 +95,7 @@ static int opus_header(AVFormatContext *avf, int idx)
return AVERROR(ENOMEM);
}
- if (os->flags & OGG_FLAG_BOS)
+ if (is_first)
return parse_opus_header(avf, st, os, priv, packet, os->psize);
if (priv->need_comments) {
@@ -129,7 +129,7 @@ static int opus_duration(uint8_t *src, int size)
return frame_size * nb_frames;
}
-static int opus_packet(AVFormatContext *avf, int idx)
+static int opus_packet(AVFormatContext *avf, int idx, int is_last)
{
struct ogg *ogg = avf->priv_data;
struct ogg_stream *os = &ogg->streams[idx];
@@ -163,34 +163,6 @@ static int opus_packet(AVFormatContext *avf, int idx)
return 1;
}
- if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) {
- int seg, d;
- int duration;
- uint8_t *last_pkt = os->buf + os->pstart;
- uint8_t *next_pkt = last_pkt;
-
- duration = 0;
- seg = os->segp;
- d = opus_duration(last_pkt, os->psize);
- if (d < 0) {
- os->pflags |= AV_PKT_FLAG_CORRUPT;
- return 0;
- }
- duration += d;
- last_pkt = next_pkt = next_pkt + os->psize;
- for (; seg < os->nsegs; seg++) {
- next_pkt += os->segments[seg];
- if (os->segments[seg] < 255 && next_pkt != last_pkt) {
- int d = opus_duration(last_pkt, next_pkt - last_pkt);
- if (d > 0)
- duration += d;
- last_pkt = next_pkt;
- }
- }
- os->lastpts =
- os->lastdts = os->granule - duration;
- }
-
if ((ret = opus_duration(packet, os->psize)) < 0)
return ret;
@@ -202,7 +174,7 @@ static int opus_packet(AVFormatContext *avf, int idx)
}
priv->cur_dts += os->pduration;
- if ((os->flags & OGG_FLAG_EOS)) {
+ if (is_last) {
int64_t skip = priv->cur_dts - os->granule + priv->pre_skip;
skip = FFMIN(skip, os->pduration);
if (skip > 0) {
diff --git a/libavformat/oggparseskeleton.c b/libavformat/oggparseskeleton.c
index 2016b16c95..1c54285aaa 100644
--- a/libavformat/oggparseskeleton.c
+++ b/libavformat/oggparseskeleton.c
@@ -23,7 +23,7 @@
#include "internal.h"
#include "oggdec.h"
-static int skeleton_header(AVFormatContext *s, int idx)
+static int skeleton_header(AVFormatContext *s, int idx, int flags)
{
struct ogg *ogg = s->priv_data;
struct ogg_stream *os = ogg->streams + idx;
@@ -36,7 +36,7 @@ static int skeleton_header(AVFormatContext *s, int idx)
st->codecpar->codec_type = AVMEDIA_TYPE_DATA;
- if ((os->flags & OGG_FLAG_EOS) && os->psize == 0)
+ if ((flags & OGG_FLAG_EOS) && os->psize == 0)
return 1;
if (os->psize < 8)
diff --git a/libavformat/oggparsespeex.c b/libavformat/oggparsespeex.c
index 0a4b32de15..d3eed6e728 100644
--- a/libavformat/oggparsespeex.c
+++ b/libavformat/oggparsespeex.c
@@ -36,7 +36,7 @@ struct speex_params {
int seq;
};
-static int speex_header(AVFormatContext *s, int idx) {
+static int speex_header(AVFormatContext *s, int idx, int flags) {
struct ogg *ogg = s->priv_data;
struct ogg_stream *os = ogg->streams + idx;
struct speex_params *spxp = os->private;
@@ -111,14 +111,14 @@ static int ogg_page_packets(struct ogg_stream *os)
return packets;
}
-static int speex_packet(AVFormatContext *s, int idx)
+static int speex_packet(AVFormatContext *s, int idx, int flags)
{
struct ogg *ogg = s->priv_data;
struct ogg_stream *os = ogg->streams + idx;
struct speex_params *spxp = os->private;
int packet_size = spxp->packet_size;
- if (os->flags & OGG_FLAG_EOS && os->lastpts != AV_NOPTS_VALUE &&
+ if (flags & OGG_FLAG_EOS && os->lastpts != AV_NOPTS_VALUE &&
os->granule > 0) {
/* first packet of final page. we have to calculate the final packet
duration here because it is the only place we know the next-to-last
diff --git a/libavformat/oggparsetheora.c b/libavformat/oggparsetheora.c
index 6cdd962759..43f5ef9fb3 100644
--- a/libavformat/oggparsetheora.c
+++ b/libavformat/oggparsetheora.c
@@ -35,7 +35,7 @@ typedef struct TheoraParams {
unsigned version;
} TheoraParams;
-static int theora_header(AVFormatContext *s, int idx)
+static int theora_header(AVFormatContext *s, int idx, int flags)
{
struct ogg *ogg = s->priv_data;
struct ogg_stream *os = ogg->streams + idx;
@@ -168,7 +168,7 @@ static uint64_t theora_gptopts(AVFormatContext *ctx, int idx, uint64_t gp,
return iframe + pframe;
}
-static int theora_packet(AVFormatContext *s, int idx)
+static int theora_packet(AVFormatContext *s, int idx, int flags)
{
struct ogg *ogg = s->priv_data;
struct ogg_stream *os = ogg->streams + idx;
@@ -179,7 +179,7 @@ static int theora_packet(AVFormatContext *s, int idx)
the total duration to the page granule to find the encoder delay and
set the first timestamp */
- if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) {
+ if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(flags & OGG_FLAG_EOS)) {
int seg;
int64_t pts;
diff --git a/libavformat/oggparsevorbis.c b/libavformat/oggparsevorbis.c
index 7c4f7624f8..58b9f98669 100644
--- a/libavformat/oggparsevorbis.c
+++ b/libavformat/oggparsevorbis.c
@@ -368,7 +368,7 @@ static int vorbis_update_metadata(AVFormatContext *s, int idx)
os->psize - 8);
}
-static int vorbis_header(AVFormatContext *s, int idx)
+static int vorbis_header(AVFormatContext *s, int idx, int is_first)
{
struct ogg *ogg = s->priv_data;
AVStream *st = s->streams[idx];
@@ -447,7 +447,7 @@ static int vorbis_header(AVFormatContext *s, int idx)
return 1;
}
-static int vorbis_packet(AVFormatContext *s, int idx)
+static int vorbis_packet(AVFormatContext *s, int idx, int is_last)
{
struct ogg *ogg = s->priv_data;
struct ogg_stream *os = ogg->streams + idx;
@@ -460,58 +460,6 @@ static int vorbis_packet(AVFormatContext *s, int idx)
if (!priv->vp)
return AVERROR_INVALIDDATA;
- /* first packet handling
- * here we parse the duration of each packet in the first page and compare
- * the total duration to the page granule to find the encoder delay and
- * set the first timestamp */
- if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS) && (int64_t)os->granule>=0) {
- int seg, d;
- uint8_t *last_pkt = os->buf + os->pstart;
- uint8_t *next_pkt = last_pkt;
-
- av_vorbis_parse_reset(priv->vp);
- duration = 0;
- seg = os->segp;
- d = av_vorbis_parse_frame_flags(priv->vp, last_pkt, 1, &flags);
- if (d < 0) {
- os->pflags |= AV_PKT_FLAG_CORRUPT;
- return 0;
- } else if (flags & VORBIS_FLAG_COMMENT) {
- vorbis_update_metadata(s, idx);
- flags = 0;
- }
- duration += d;
- last_pkt = next_pkt = next_pkt + os->psize;
- for (; seg < os->nsegs; seg++) {
- if (os->segments[seg] < 255) {
- int d = av_vorbis_parse_frame_flags(priv->vp, last_pkt, 1, &flags);
- if (d < 0) {
- duration = os->granule;
- break;
- } else if (flags & VORBIS_FLAG_COMMENT) {
- vorbis_update_metadata(s, idx);
- flags = 0;
- }
- duration += d;
- last_pkt = next_pkt + os->segments[seg];
- }
- next_pkt += os->segments[seg];
- }
- os->lastpts =
- os->lastdts = os->granule - duration;
-
- if (!os->granule && duration) //hack to deal with broken files (Ticket3710)
- os->lastpts = os->lastdts = AV_NOPTS_VALUE;
-
- if (s->streams[idx]->start_time == AV_NOPTS_VALUE) {
- s->streams[idx]->start_time = FFMAX(os->lastpts, 0);
- if (s->streams[idx]->duration != AV_NOPTS_VALUE)
- s->streams[idx]->duration -= s->streams[idx]->start_time;
- }
- priv->final_pts = AV_NOPTS_VALUE;
- av_vorbis_parse_reset(priv->vp);
- }
-
/* parse packet duration */
if (os->psize > 0) {
duration = av_vorbis_parse_frame_flags(priv->vp, os->buf + os->pstart, 1, &flags);
@@ -569,7 +517,7 @@ static int vorbis_packet(AVFormatContext *s, int idx)
* here we save the pts of the first packet in the final page, sum up all
* packet durations in the final page except for the last one, and compare
* to the page granule to find the duration of the final packet */
- if (os->flags & OGG_FLAG_EOS) {
+ if (is_last) {
if (os->lastpts != AV_NOPTS_VALUE) {
priv->final_pts = os->lastpts;
priv->final_duration = 0;
diff --git a/libavformat/oggparsevp8.c b/libavformat/oggparsevp8.c
index 676b3a0f8e..679ef64d76 100644
--- a/libavformat/oggparsevp8.c
+++ b/libavformat/oggparsevp8.c
@@ -27,7 +27,7 @@
#define VP8_HEADER_SIZE 26
-static int vp8_header(AVFormatContext *s, int idx)
+static int vp8_header(AVFormatContext *s, int idx, int flags)
{
struct ogg *ogg = s->priv_data;
struct ogg_stream *os = ogg->streams + idx;
@@ -98,14 +98,14 @@ static uint64_t vp8_gptopts(AVFormatContext *s, int idx,
return pts;
}
-static int vp8_packet(AVFormatContext *s, int idx)
+static int vp8_packet(AVFormatContext *s, int idx, int flags)
{
struct ogg *ogg = s->priv_data;
struct ogg_stream *os = ogg->streams + idx;
uint8_t *p = os->buf + os->pstart;
if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) &&
- !(os->flags & OGG_FLAG_EOS)) {
+ !(flags & OGG_FLAG_EOS)) {
int seg;
int duration;
uint8_t *last_pkt = p;
--
2.49.1
_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2025-10-01 23:03 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-10-01 23:02 [FFmpeg-devel] [PATCH] Cleanup packet-level BOS/EOS logic. (PR #20640) toots via ffmpeg-devel
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror http://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ http://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git