Add video-player -h, -w, and -z options to select the window size.

Restore extradata codec support that was previously removed when libavcodec
was updated and no replacement was known yet. This makes many codecs start
working again.

Convert video-player to C while here and remove dispd support.
This commit is contained in:
Jonas 'Sortie' Termansen 2024-01-14 17:51:26 +01:00
parent 979071b0b7
commit e7fae57678
2 changed files with 122 additions and 113 deletions

View File

@ -1,7 +1,7 @@
diff -Paur --no-dereference -- video-player.upstream/Makefile video-player/Makefile
--- video-player.upstream/Makefile
+++ video-player/Makefile
@@ -0,0 +1,36 @@
@@ -0,0 +1,29 @@
+include ../../../build-aux/compiler.mak
+include ../../../build-aux/version.mak
+include ../../../build-aux/dirs.mak
@ -9,28 +9,21 @@ diff -Paur --no-dereference -- video-player.upstream/Makefile video-player/Makef
+PKG_CONFIG?=pkg-config
+
+OPTLEVEL?=-g -O2
+CXXFLAGS?=$(OPTLEVEL)
+CFLAGS?=$(OPTLEVEL)
+
+CPPFLAGS:=$(CPPFLAGS)
+CXXFLAGS:=$(CXXFLAGS) -Wall -Wextra -fno-exceptions -fno-rtti
+CFLAGS:=$(CFLAGS) -Wall -Wextra
+
+BINARY:=video-player
+LIBS!=$(PKG_CONFIG) --libs libavcodec libavformat libswscale
+
+DISPLAY:=$(shell $(LD) -ldisplay -o /dev/null 2>/dev/null && echo 1)
+ifeq ($(DISPLAY),1)
+LIBS:=$(LIBS) -ldisplay
+CPPFLAGS:=$(CPPFLAGS) -DDISPLAY
+else
+LIBS:=$(LIBS) -ldispd
+endif
+
+all: $(BINARY)
+
+.PHONY: all install clean
+
+%: %.cpp
+ $(CXX) -std=gnu++11 $(CXXFLAGS) $(CPPFLAGS) $< -o $@ $(LIBS)
+%: %.c
+ $(CC) -std=gnu11 $(CFLAGS) $(CPPFLAGS) $< -o $@ $(LIBS)
+
+install: all
+ mkdir -p $(DESTDIR)$(BINDIR)
@ -38,16 +31,32 @@ diff -Paur --no-dereference -- video-player.upstream/Makefile video-player/Makef
+
+clean:
+ rm -f $(BINARY)
diff -Paur --no-dereference -- video-player.upstream/video-player.cpp video-player/video-player.cpp
--- video-player.upstream/video-player.cpp
+++ video-player/video-player.cpp
@@ -0,0 +1,302 @@
+#define __STDC_CONSTANT_MACROS
+#define __STDC_LIMIT_MACROS
diff -Paur --no-dereference -- video-player.upstream/video-player.c video-player/video-player.c
--- video-player.upstream/video-player.c
+++ video-player/video-player.c
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 2016, 2021, 2022, 2024 Jonas 'Sortie' Termansen.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * video-player.c
+ * Play videos.
+ */
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <error.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
@ -55,110 +64,111 @@ diff -Paur --no-dereference -- video-player.upstream/video-player.cpp video-play
+#include <timespec.h>
+#include <unistd.h>
+
+#ifdef DISPLAY
+#include <display.h>
+#else
+#include <dispd.h>
+#endif
+
+extern "C" {
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#include <libswscale/swscale.h>
+} // extern "C"
+
+uint32_t WINDOW_ID = 0;
+uint32_t WINDOW_WIDTH = 0;
+uint32_t WINDOW_HEIGHT = 0;
+static uint32_t WINDOW_ID = 0;
+static uint32_t WINDOW_WIDTH = 0;
+static uint32_t WINDOW_HEIGHT = 0;
+
+bool need_show = true;
+bool need_exit = false;
+static int force_width = 0;
+static int force_height = 0;
+static int zoom = 100;
+
+uint32_t* framebuffer = NULL;
+size_t framebuffer_size = 0;
+static bool need_show = true;
+static bool need_exit = false;
+
+void on_disconnect(void*)
+static uint32_t* framebuffer = NULL;
+static size_t framebuffer_size = 0;
+
+static void on_disconnect(void* ctx)
+{
+ need_exit = true;
+}
+
+void on_quit(void*, uint32_t window_id)
+static void on_quit(void* ctx, uint32_t window_id)
+{
+ if ( window_id != WINDOW_ID )
+ return;
+ need_exit = true;
+}
+
+void on_resize(void*, uint32_t window_id, uint32_t width, uint32_t height)
+static void on_resize(void* ctx, uint32_t window_id, uint32_t width,
+ uint32_t height)
+{
+ if ( window_id != WINDOW_ID )
+ return;
+ WINDOW_WIDTH = width;
+ WINDOW_HEIGHT = height;
+ force_width = width;
+ force_height = height;
+ zoom = 100;
+}
+
+void on_keyboard(void*, uint32_t window_id, uint32_t)
+static void on_keyboard(void* ctx, uint32_t window_id, uint32_t codepoint)
+{
+ if ( window_id != WINDOW_ID )
+ return;
+}
+
+#ifdef DISPLAY
+static void DisplayVideoFrame(AVFrame* frame, struct display_connection* connection)
+#else
+static void DisplayVideoFrame(AVFrame* frame, struct dispd_window* window)
+#endif
+static void display_video_frame(AVFrame* frame,
+ struct display_connection* connection)
+{
+#ifdef DISPLAY
+ if ( need_show )
+ {
+ WINDOW_WIDTH =
+ force_width ? force_width : (frame->width * zoom) / 100;
+ WINDOW_HEIGHT =
+ force_height ? force_height : (frame->height * zoom) / 100;
+ display_resize_window(connection, WINDOW_ID, WINDOW_WIDTH,
+ WINDOW_HEIGHT);
+ }
+
+ if ( !WINDOW_WIDTH || !WINDOW_HEIGHT )
+ return;
+
+ size_t framebuffer_needed = sizeof(uint32_t) * WINDOW_WIDTH * WINDOW_HEIGHT;
+ if ( framebuffer_size != framebuffer_needed )
+ {
+ framebuffer = (uint32_t*) realloc(framebuffer, framebuffer_size = framebuffer_needed);
+ framebuffer =
+ (uint32_t*) realloc(framebuffer,
+ framebuffer_size = framebuffer_needed);
+ memset(framebuffer, 255, framebuffer_needed);
+ }
+ uint32_t width = WINDOW_WIDTH;
+ uint32_t height = WINDOW_HEIGHT;
+#else
+ struct dispd_framebuffer* window_fb = dispd_begin_render(window);
+ uint32_t width = dispd_get_framebuffer_width(window_fb);
+ uint32_t height = dispd_get_framebuffer_height(window_fb);
+ uint32_t* framebuffer = (uint32_t*) dispd_get_framebuffer_data(window_fb);
+#endif
+
+ SwsContext* sws_ctx = sws_getContext(frame->width, frame->height,
+ (AVPixelFormat) frame->format, width,
+ height, AV_PIX_FMT_RGB32, SWS_BILINEAR,
+ NULL, NULL, NULL);
+ struct SwsContext* sws_ctx =
+ sws_getContext(frame->width, frame->height,
+ (enum AVPixelFormat) frame->format, width, height,
+ AV_PIX_FMT_RGB32, SWS_BILINEAR, NULL, NULL, NULL);
+ assert(sws_ctx);
+
+ uint8_t* data_arr[1] = { (uint8_t*) framebuffer };
+ int stride_arr[1] = { (int) (sizeof(framebuffer[0]) * width) };
+ sws_scale(sws_ctx, frame->data, frame->linesize, 0, frame->height, data_arr,
+ stride_arr);
+
+ sws_scale(sws_ctx, (const uint8_t * const*) frame->data, frame->linesize, 0,
+ frame->height, data_arr, stride_arr);
+
+ sws_freeContext(sws_ctx);
+
+#ifdef DISPLAY
+ display_render_window(connection, WINDOW_ID, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, framebuffer);
+ display_render_window(connection, WINDOW_ID, 0, 0, WINDOW_WIDTH,
+ WINDOW_HEIGHT, framebuffer);
+
+ struct display_event_handlers handlers;
+ memset(&handlers, 0, sizeof(handlers));
+ handlers.disconnect_handler = on_disconnect;
+ handlers.quit_handler = on_quit;
+ handlers.resize_handler = on_resize;
+ handlers.keyboard_handler = on_keyboard;
+ while ( display_poll_event(connection, &handlers) == 0 );
+#else
+ dispd_finish_render(window_fb);
+#endif
+ if ( need_show )
+ {
+ display_show_window(connection, WINDOW_ID);
+ need_show = false;
+ }
+}
+
+#ifdef DISPLAY
+bool PlayVideo(const char* path, struct display_connection* connection)
+#else
+bool PlayVideo(const char* path, struct dispd_window* connection)
+#endif
+bool play_video(const char* path, struct display_connection* connection)
+{
+ need_show = true;
+
+ bool ret = false;
+ int av_error;
+ AVFormatContext* format_ctx = NULL;
@ -176,13 +186,13 @@ diff -Paur --no-dereference -- video-player.upstream/video-player.cpp video-play
+
+ if ( (av_error = avformat_open_input(&format_ctx, path, NULL, NULL)) < 0 )
+ {
+ error(0, 0, "%s: cannot open: %i\n", path, av_error);
+ warnx("%s: cannot open: %i\n", path, av_error);
+ goto cleanup_done;
+ }
+
+ if ( (av_error = avformat_find_stream_info(format_ctx, NULL)) < 0 )
+ {
+ error(0, 0, "%s: avformat_find_stream_info: %i\n", path, av_error);
+ warnx("%s: avformat_find_stream_info: %i\n", path, av_error);
+ goto cleanup_input;
+ }
+
@ -198,23 +208,28 @@ diff -Paur --no-dereference -- video-player.upstream/video-player.cpp video-play
+
+ if ( !video_stream )
+ {
+ error(0, 0, "%s: no video stream found\n", path);
+ warnx("%s: no video stream found\n", path);
+ goto cleanup_input;
+ }
+
+ if ( video_codec && !(video_codec_ctx = avcodec_alloc_context3(video_codec)))
+ if ( video_codec &&
+ !(video_codec_ctx = avcodec_alloc_context3(video_codec)))
+ goto cleanup_input;
+ if ( audio_codec && !(audio_codec_ctx = avcodec_alloc_context3(audio_codec)))
+ if ( audio_codec &&
+ !(audio_codec_ctx = avcodec_alloc_context3(audio_codec)))
+ goto cleanup_video_codec_ctx;
+
+
+ if ( video_codec_ctx )
+ {
+ video_codec_ctx->extradata = video_stream->codecpar->extradata;
+ video_codec_ctx->extradata_size = video_stream->codecpar->extradata_size;
+ if ( (av_error = avcodec_open2(video_codec_ctx, NULL, NULL)) < 0 )
+ goto cleanup_audio_codec_ctx;
+ }
+ if ( audio_codec_ctx )
+ {
+ audio_codec_ctx->extradata = audio_stream->codecpar->extradata;
+ audio_codec_ctx->extradata_size = audio_stream->codecpar->extradata_size;
+ if ( (av_error = avcodec_open2(audio_codec_ctx, NULL, NULL)) < 0 )
+ goto cleanup_audio_codec_ctx;
+ }
@ -247,12 +262,21 @@ diff -Paur --no-dereference -- video-player.upstream/video-player.cpp video-play
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ }
+
+ DisplayVideoFrame(video_frame, connection);
+ display_video_frame(video_frame, connection);
+
+ uintmax_t usecs = video_codec_ctx->ticks_per_frame * 1000000 *
+ video_codec_ctx->time_base.num /
+ video_codec_ctx->time_base.den;
+ next_frame_at = timespec_add(next_frame_at, timespec_make(0, usecs * 1000));
+ next_frame_at =
+ timespec_add(next_frame_at, timespec_make(0, usecs * 1000));
+
+ struct display_event_handlers handlers;
+ memset(&handlers, 0, sizeof(handlers));
+ handlers.disconnect_handler = on_disconnect;
+ handlers.quit_handler = on_quit;
+ handlers.resize_handler = on_resize;
+ handlers.keyboard_handler = on_keyboard;
+ while ( display_poll_event(connection, &handlers) == 0 );
+ }
+ if ( av_error != AVERROR(EAGAIN) && av_error != AVERROR_EOF )
+ goto break_decode_loop;
@ -280,12 +304,14 @@ diff -Paur --no-dereference -- video-player.upstream/video-player.cpp video-play
+cleanup_audio_codec_ctx:
+ if ( audio_codec_ctx )
+ {
+ audio_codec_ctx->extradata = NULL;
+ avcodec_close(audio_codec_ctx);
+ av_free(audio_codec_ctx);
+ }
+cleanup_video_codec_ctx:
+ if ( video_codec_ctx )
+ {
+ video_codec_ctx->extradata = NULL;
+ avcodec_close(video_codec_ctx);
+ av_free(video_codec_ctx);
+ }
@ -297,50 +323,32 @@ diff -Paur --no-dereference -- video-player.upstream/video-player.cpp video-play
+
+int main(int argc, char* argv[])
+{
+#ifdef DISPLAY
+ int opt;
+ while ( (opt = getopt(argc, argv, "h:w:z:")) != -1 )
+ {
+ switch ( opt )
+ {
+ case 'h': force_height = atoi(optarg); break;
+ case 'w': force_width = atoi(optarg); break;
+ case 'z': zoom = atoi(optarg); break;
+ default: return 1;
+ }
+ }
+
+ struct display_connection* connection = display_connect_default();
+ if ( !connection )
+ error(1, errno, "Could not connect to display server");
+#else
+ if ( !isatty(0) )
+ error(1, errno, "standard input");
+ if ( !dispd_initialize(&argc, &argv) )
+ error(1, 0, "couldn't initialize dispd library");
+ struct dispd_session* session = dispd_attach_default_session();
+ if ( !session )
+ error(1, 0, "couldn't attach to dispd default session");
+ if ( !dispd_session_setup_game_rgba(session) )
+ error(1, 0, "couldn't setup dispd rgba session");
+ struct dispd_window* window = dispd_create_window_game_rgba(session);
+ if ( !window )
+ error(1, 0, "couldn't create dispd rgba window");
+ struct dispd_window* connection = window;
+#endif
+
+#ifdef DISPLAY
+ WINDOW_WIDTH = 800;
+ WINDOW_HEIGHT = 450;
+ err(1, "Could not connect to display server");
+
+ display_create_window(connection, WINDOW_ID);
+ display_resize_window(connection, WINDOW_ID, WINDOW_WIDTH, WINDOW_HEIGHT);
+ display_show_window(connection, WINDOW_ID);
+#endif
+
+ for ( int i = 1; i < argc; i++ )
+ for ( int i = optind; i < argc; i++ )
+ {
+#ifdef DISPLAY
+ display_title_window(connection, WINDOW_ID, argv[i]);
+#endif
+ if ( !PlayVideo(argv[i], connection) )
+ if ( !play_video(argv[i], connection) )
+ return 1;
+ }
+
+#ifdef DISPLAY
+ display_disconnect(connection);
+#else
+ dispd_destroy_window(window);
+ dispd_detach_session(session);
+#endif
+
+ return 0;
+}

View File

@ -1,3 +1,4 @@
NAME=video-player
BUILD_LIBRARIES=libavcodec
BUILD_SYSTEM=sortix-usual-makefile
LICENSE=ISC