PR #25735 opened by Kilian (lusoris)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25735
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25735.patch

When flushing or renaming a segment fails, `dash_flush()` leaves its stream 
loop and skips writing the manifest, but it still runs the `window_size` 
eviction. Old media segments are then deleted while the manifest on disk still 
references them. This change skips the eviction unless the flush succeeded.

Reported in the review of pull request 25619.

## Reproducer

Two streams (testsrc video, sine audio), `-f dash -seg_duration 0.5 
-window_size 1 -extra_window_size 0`. The write of the second audio segment is 
made to fail in one of two ways:

- **Rename fails:** a non-empty directory sits at the final path 
`chunk-stream1-00002.m4s`.
- **Write fails:** `chunk-stream1-00002.m4s.tmp` is a symlink to `/dev/full`.

After the run, every media file named in the retained MPD is checked for 
existence.

| Case | Tree | ffmpeg exit | Files the retained MPD names but that are missing 
|
|---|---|---|---|
| rename fails | master | 0 | chunk-stream0-00001.m4s |
| rename fails | master + this change | 0 | none |
| write fails | pull request 25619 | 228 (ENOSPC) | chunk-stream0-00001.m4s |
| write fails | pull request 25619 + this change | 228 (ENOSPC) | none |

The exit status of 0 in the rename case comes from `dash_write_trailer()` 
discarding the `dash_flush()` result on master; pull request 25619 changes that.

## Tests

`make fate-dash-big-init fate-dash-mpd-timing fate-dash-seek-reference 
fate-dash-seek-zero fate-hls-discont-start fate-hls-fmp4-big-init 
fate-hls-iframes-single-fmp4 fate-hls-iframes-single-mpegts 
fate-hls-independent-segments fate-hls-playlist-type-event 
fate-hls-playlist-type-vod fate-hls-round-durations fate-hls-start-number 
fate-source` passes.

## Similar code in other muxers

Other segment muxers that delete old files were checked for the same pattern. 
They are not changed here:

- **hlsenc:** a segment rename result is not checked before the old segments 
are deleted, and close errors on the playlist are discarded.
- **segment:** list entries are trimmed after a trailer failure.
- **smoothstreamingenc:** an open, parse or rename failure breaks out of the 
loop, and the unconditional window removal still runs.
- **hdsenc:** close errors are discarded before window removal.



>From 4b4ba3d3c6eb892568bb4bb373ce3bcdb3e013ec Mon Sep 17 00:00:00 2001
From: lusoris <[email protected]>
Date: Tue, 3 Nov 2026 21:46:45 +0100
Subject: [PATCH] avformat/dashenc: do not evict old segments after a failed
 segment

dash_flush() breaks out of its stream loop when flushing or renaming a
segment fails, but then still runs the window_size eviction. The
manifest is not updated in that case, so the eviction deletes media
files that the last written manifest still references.

Reproduced by making the rename of the second audio segment fail
(target path is a non-empty directory) with -window_size 1 -extra_window_size 
0: the
retained MPD keeps startNumber=1 while chunk-stream0-00001.m4s is
deleted. With this change every file the retained MPD names still
exists. The same holds when the temporary segment file is on /dev/full.

Skip the eviction unless the flush succeeded.

Signed-off-by: lusoris <[email protected]>
---
 libavformat/dashenc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 36f39bd083a..42d2dd7cac4 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -1858,7 +1858,7 @@ static int dash_flush(AVFormatContext *s, int final, int 
stream)
         os->pos += range_length;
     }
 
-    if (c->window_size) {
+    if (ret >= 0 && c->window_size) {
         for (i = 0; i < s->nb_streams; i++) {
             OutputStream *os = &c->streams[i];
             int remove_count = os->nb_segments - c->window_size - 
c->extra_window_size;
-- 
2.54.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to