Commit 8fdf7f7241 for ffmpeg

commit 8fdf7f7241a8ab990b41177223b54adec646c247
Author: Michael Niedermayer <michael@niedermayer.cc>
Date:   Thu Oct 15 14:15:52 2026 +0200

    ffplay: keep the list in the window instead of the VideoState

    The list is an overlay of the window, so one list serves whatever
    stream is playing.

    Assisted-by: Claude

diff --git a/fftools/ffplay.c b/fftools/ffplay.c
index ecb2151509..2b2e9b583e 100644
--- a/fftools/ffplay.c
+++ b/fftools/ffplay.c
@@ -295,7 +295,6 @@ typedef struct VideoState {
     SDL_Texture *vid_texture;
     SDL_AudioDeviceID audio_dev;
     int64_t audio_callback_time;
-    ListView *chapter_list;

     int subtitle_stream;
     AVStream *subtitle_st;
@@ -373,7 +372,8 @@ static const char *video_codec_name;
 double rdftspeed = 0.02;
 static int64_t cursor_last_shown;
 static int cursor_hidden = 0;
-/* the key that pins a list when it is released, 0 for none */
+static ListView *list;
+/* the key that pins the list when it is released, 0 for none */
 static SDL_Keycode list_key;
 static const char **vfilters_list = NULL;
 static int nb_vfilters = 0;
@@ -1064,8 +1064,8 @@ static int chapter_list_show(VideoState *is, int chapter)
         if (ch->end != AV_NOPTS_VALUE && ch->end > ch->start && (uint64_t)ch->end - ch->start <= INT64_MAX)
             entries[i].length = av_rescale_q(ch->end - ch->start, ch->time_base, AV_TIME_BASE_Q);
     }
-    list_view_set_playing(is->chapter_list, current_chapter(is));
-    ret = list_view_show(is->chapter_list, entries, is->ic->nb_chapters, chapter);
+    list_view_set_playing(list, current_chapter(is));
+    ret = list_view_show(list, entries, is->ic->nb_chapters, chapter);
     av_free(entries);
     return ret;
 }
@@ -1073,7 +1073,7 @@ static int chapter_list_show(VideoState *is, int chapter)
 static void chapter_list_pin(VideoState *is)
 {
     if (chapter_list_show(is, current_chapter(is)) >= 0)
-        list_view_pin(is->chapter_list, 1);
+        list_view_pin(list, 1);
 }

 static void video_image_display(VideoState *is)
@@ -1455,7 +1455,6 @@ static void stream_close(VideoState *is)
         SDL_DestroyTexture(is->vid_texture);
     if (is->sub_texture)
         SDL_DestroyTexture(is->sub_texture);
-    list_view_free(&is->chapter_list);
     av_free(is);
 }

@@ -1464,6 +1463,7 @@ static void do_exit(VideoState *is)
     if (is) {
         stream_close(is);
     }
+    list_view_free(&list);
     if (renderer)
         SDL_DestroyRenderer(renderer);
     if (vk_renderer)
@@ -1522,7 +1522,7 @@ static int video_open(VideoState *is)

     is->width  = w;
     is->height = h;
-    list_view_set_size(is->chapter_list, w, h);
+    list_view_set_size(list, w, h);

     return 0;
 }
@@ -1539,7 +1539,7 @@ static void video_display(VideoState *is)
         video_audio_display(is);
     else if (is->video_st)
         video_image_display(is);
-    list_view_draw(is->chapter_list);
+    list_view_draw(list);
     SDL_RenderPresent(renderer);
 }

@@ -3592,8 +3592,7 @@ static VideoState *stream_open(const char *filename,
     is->last_subtitle_stream = is->subtitle_stream = -1;
     is->filename = av_strdup(filename);
     is->id = ++last_stream_id;
-    is->chapter_list = list_view_alloc(renderer);
-    if (!is->filename || !is->chapter_list)
+    if (!is->filename)
         goto fail;
     is->iformat = iformat;
     is->seek_by_bytes   = seek_by_bytes;
@@ -3767,9 +3766,9 @@ static void refresh_loop_wait_event(VideoState *is, SDL_Event *event) {
                 continue;
         }
         remaining_time = REFRESH_RATE;
-        if (list_view_visible(is->chapter_list))
-            list_view_set_playing(is->chapter_list, current_chapter(is));
-        if (list_view_update(is->chapter_list))
+        if (list_view_visible(list))
+            list_view_set_playing(list, current_chapter(is));
+        if (list_view_update(list))
             is->force_refresh = 1;
         if (is->show_mode != SHOW_MODE_NONE && (!is->paused || is->force_refresh))
             video_refresh(is, &remaining_time);
@@ -3815,7 +3814,7 @@ static void event_loop(VideoState *cur_stream)
         refresh_loop_wait_event(cur_stream, &event);
         switch (event.type) {
         case SDL_KEYDOWN:
-            if (exit_on_keydown || (!list_view_pinned(cur_stream->chapter_list) &&
+            if (exit_on_keydown || (!list_view_pinned(list) &&
                                     (event.key.keysym.sym == SDLK_ESCAPE || event.key.keysym.sym == SDLK_q))) {
                 do_exit(cur_stream);
                 break;
@@ -3823,10 +3822,10 @@ static void event_loop(VideoState *cur_stream)
             // If we don't yet have a window, skip all key events, because read_thread might still be initializing...
             if (!cur_stream->width)
                 continue;
-            if (list_view_pinned(cur_stream->chapter_list)) {
+            if (list_view_pinned(list)) {
                 if (event.key.keysym.sym == SDLK_PAGEUP || event.key.keysym.sym == SDLK_PAGEDOWN)
                     seek_chapter(cur_stream, current_chapter(cur_stream) + (event.key.keysym.sym == SDLK_PAGEUP ? 1 : -1));
-                else if ((chosen = list_view_key(cur_stream->chapter_list, event.key.keysym.sym)) >= 0)
+                else if ((chosen = list_view_key(list, event.key.keysym.sym)) >= 0)
                     seek_chapter(cur_stream, chosen);
                 break;
             }
@@ -3872,7 +3871,7 @@ static void event_loop(VideoState *cur_stream)
                 break;
             case SDLK_RETURN:
             case SDLK_KP_ENTER:
-                if (list_view_visible(cur_stream->chapter_list) && (chosen = list_view_selected(cur_stream->chapter_list)) >= 0)
+                if (list_view_visible(list) && (chosen = list_view_selected(list)) >= 0)
                     seek_chapter(cur_stream, chosen);
                 break;
             case SDLK_w:
@@ -3945,20 +3944,20 @@ static void event_loop(VideoState *cur_stream)
             list_key = 0;
             break;
         case SDL_TEXTINPUT:
-            if (list_view_pinned(cur_stream->chapter_list))
-                list_view_text(cur_stream->chapter_list, event.text.text);
+            if (list_view_pinned(list))
+                list_view_text(list, event.text.text);
             break;
         case SDL_MOUSEWHEEL:
-            if (list_view_visible(cur_stream->chapter_list))
-                list_view_move(cur_stream->chapter_list, -event.wheel.y);
+            if (list_view_visible(list))
+                list_view_move(list, -event.wheel.y);
             break;
         case SDL_MOUSEBUTTONDOWN:
             if (exit_on_mousedown) {
                 do_exit(cur_stream);
                 break;
             }
-            if (event.button.button == SDL_BUTTON_LEFT && list_view_visible(cur_stream->chapter_list) &&
-                list_view_click(cur_stream->chapter_list, event.button.x, event.button.y, &chosen)) {
+            if (event.button.button == SDL_BUTTON_LEFT && list_view_visible(list) &&
+                list_view_click(list, event.button.x, event.button.y, &chosen)) {
                 if (chosen >= 0)
                     seek_chapter(cur_stream, chosen);
                 break;
@@ -3981,7 +3980,7 @@ static void event_loop(VideoState *cur_stream)
             }
             cursor_last_shown = av_gettime_relative();
             if (event.type == SDL_MOUSEMOTION)
-                list_view_hover(cur_stream->chapter_list, event.motion.x, event.motion.y);
+                list_view_hover(list, event.motion.x, event.motion.y);
             if (event.type == SDL_MOUSEBUTTONDOWN) {
                 if (event.button.button != SDL_BUTTON_RIGHT)
                     break;
@@ -4019,7 +4018,7 @@ static void event_loop(VideoState *cur_stream)
         case SDL_WINDOWEVENT:
             switch (event.window.event) {
                 case SDL_WINDOWEVENT_LEAVE:
-                    list_view_hover(cur_stream->chapter_list, -1, -1);
+                    list_view_hover(list, -1, -1);
                     break;
                 case SDL_WINDOWEVENT_SIZE_CHANGED:
                     screen_width  = cur_stream->width  = event.window.data1;
@@ -4028,7 +4027,7 @@ static void event_loop(VideoState *cur_stream)
                         SDL_DestroyTexture(cur_stream->vis_texture);
                         cur_stream->vis_texture = NULL;
                     }
-                    list_view_set_size(cur_stream->chapter_list, screen_width, screen_height);
+                    list_view_set_size(list, screen_width, screen_height);
                     if (vk_renderer)
                         vk_renderer_resize(vk_renderer, screen_width, screen_height);
                     av_fallthrough;
@@ -4383,6 +4382,11 @@ int main(int argc, char **argv)
         }
     }

+    list = list_view_alloc(renderer);
+    if (!list) {
+        av_log(NULL, AV_LOG_FATAL, "Could not allocate the list\n");
+        do_exit(NULL);
+    }
     is = stream_open(input_filename, file_iformat);
     if (!is) {
         av_log(NULL, AV_LOG_FATAL, "Failed to initialize VideoState!\n");