sortix-mirror/ports/video-player/video-player.patch
Jonas 'Sortie' Termansen 9588b0d3db Add ports to the Sortix repository.
This change imports the ports collection from the former porttix and srctix
repositories and converts them to port(5) files with metadata pointing to
the upstream release tarballs with patches checked into this repository.
Ports are now developed and versioned along with the operating system and
are automatically built per the PACKAGES environment variable. The patches
are licensed under the same license as the relevant ports.

Tix has gained support for the new port(5) format. tix-port(8) is the new
high level ports build even point that handles downloading pstream releases
into the new mirror cache directory, applying the patches, building the port
with the lower-level tix-build(8), and finally installing the binary
package. The new tix-vars(8) program parses port(5) files and the new
tix-rmdiff(8) program produces input for tix-rmpatch(8).

The old doc/ directory is discontinued in favor of manual pages documenting
the new ports system.

The obsolete porttix-create(8) and srctix-create(8) programs are removed.
2022-06-13 22:29:53 +02:00

358 lines
10 KiB
Diff

diff -Paur --no-dereference -- video-player.upstream/Makefile video-player/Makefile
--- video-player.upstream/Makefile
+++ video-player/Makefile
@@ -0,0 +1,36 @@
+include ../../../build-aux/compiler.mak
+include ../../../build-aux/version.mak
+include ../../../build-aux/dirs.mak
+
+PKG_CONFIG?=pkg-config
+
+OPTLEVEL?=-g -O2
+CXXFLAGS?=$(OPTLEVEL)
+
+CPPFLAGS:=$(CPPFLAGS)
+CXXFLAGS:=$(CXXFLAGS) -Wall -Wextra -fno-exceptions -fno-rtti
+
+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)
+
+install: all
+ mkdir -p $(DESTDIR)$(BINDIR)
+ install $(BINARY) $(DESTDIR)$(BINDIR)
+
+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,313 @@
+#define __STDC_CONSTANT_MACROS
+#define __STDC_LIMIT_MACROS
+
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#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;
+
+bool need_show = true;
+bool need_exit = false;
+
+uint32_t* framebuffer = NULL;
+size_t framebuffer_size = 0;
+
+void on_disconnect(void*)
+{
+ need_exit = true;
+}
+
+void on_quit(void*, 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)
+{
+ if ( window_id != WINDOW_ID )
+ return;
+ WINDOW_WIDTH = width;
+ WINDOW_HEIGHT = height;
+}
+
+void on_keyboard(void*, uint32_t window_id, uint32_t)
+{
+ 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
+{
+#ifdef DISPLAY
+ 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);
+ 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);
+ 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_freeContext(sws_ctx);
+
+#ifdef DISPLAY
+ 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
+}
+
+#ifdef DISPLAY
+bool PlayVideo(const char* path, struct display_connection* connection)
+#else
+bool PlayVideo(const char* path, struct dispd_window* connection)
+#endif
+{
+ bool ret = false;
+ int av_error;
+ AVFormatContext* format_ctx = NULL;
+ int video_stream_id;
+ int audio_stream_id;
+ AVStream* video_stream = NULL;
+ AVStream* audio_stream = NULL;
+ AVCodec* video_codec = NULL;
+ AVCodec* audio_codec = NULL;
+ AVCodecContext* video_codec_ctx = NULL;
+ AVCodecContext* audio_codec_ctx = NULL;
+ AVFrame* video_frame = NULL;
+ AVFrame* audio_frame = NULL;
+ AVPacket packet;
+
+ if ( (av_error = avformat_open_input(&format_ctx, path, NULL, NULL)) < 0 )
+ {
+ error(0, 0, "%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);
+ goto cleanup_input;
+ }
+
+ video_stream_id = av_find_best_stream(format_ctx, AVMEDIA_TYPE_VIDEO, -1,
+ -1, &video_codec, 0);
+ audio_stream_id = av_find_best_stream(format_ctx, AVMEDIA_TYPE_AUDIO, -1,
+ -1, &audio_codec, 0);
+
+ if ( 0 <= video_stream_id )
+ video_stream = format_ctx->streams[video_stream_id];
+ if ( 0 <= audio_stream_id )
+ audio_stream = format_ctx->streams[audio_stream_id];
+
+ if ( !video_stream )
+ {
+ error(0, 0, "%s: no video stream found\n", path);
+ goto cleanup_input;
+ }
+
+ 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)))
+ goto cleanup_video_codec_ctx;
+
+ if ( video_codec_ctx )
+ {
+ video_codec_ctx->extradata = video_stream->codec->extradata;
+ video_codec_ctx->extradata_size = video_stream->codec->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->codec->extradata;
+ audio_codec_ctx->extradata_size = audio_stream->codec->extradata_size;
+ if ( (av_error = avcodec_open2(audio_codec_ctx, NULL, NULL)) < 0 )
+ goto cleanup_audio_codec_ctx;
+ }
+
+ if ( !(video_frame = av_frame_alloc()) )
+ goto cleanup_audio_codec_ctx;
+ if ( !(audio_frame = av_frame_alloc()) )
+ goto cleanup_video_frame;
+
+ struct timespec next_frame_at;
+ clock_gettime(CLOCK_MONOTONIC, &next_frame_at);
+
+ while ( !need_exit && 0 <= (av_error = av_read_frame(format_ctx, &packet)) )
+ {
+ int stream_index = packet.stream_index;
+ int packet_off = 0;
+ while ( stream_index == video_stream->index && packet_off < packet.size )
+ {
+ packet.data += packet_off; packet.size -= packet_off;
+ int got_frame;
+ int bytes_used = avcodec_decode_video2(video_codec_ctx, video_frame,
+ &got_frame, &packet);
+ packet.data -= packet_off; packet.size += packet_off;
+
+ if ( (av_error = bytes_used) < 0 )
+ goto break_decode_loop;
+ if ( !got_frame )
+ break;
+ packet_off += bytes_used;
+
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ while ( timespec_le(now, next_frame_at) )
+ {
+ struct timespec left = timespec_sub(next_frame_at, now);
+ clock_nanosleep(CLOCK_MONOTONIC, 0, &left, NULL);
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ }
+
+ DisplayVideoFrame(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));
+ }
+ while ( stream_index == audio_stream->index && packet_off < packet.size )
+ {
+ // TODO: Add sound support when an backend is available.
+ packet_off = packet.size;
+ }
+ }
+break_decode_loop:
+
+ // TODO: Determine whether the are here because of EOF or whether an error
+ // occured and we need to print an error.
+ // TODO: Do we need to clean up the last packet or does the av_read_frame
+ // function do that for us upon error?
+ ret = true;
+
+goto cleanup_audio_frame;
+cleanup_audio_frame:
+ if ( audio_frame )
+ av_frame_free(&audio_frame);
+cleanup_video_frame:
+ if ( video_frame )
+ av_frame_free(&video_frame);
+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);
+ }
+cleanup_input:
+ avformat_close_input(&format_ctx);
+cleanup_done:
+ return ret;
+}
+
+int main(int argc, char* argv[])
+{
+#ifdef DISPLAY
+ 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
+ av_register_all();
+
+#ifdef DISPLAY
+ WINDOW_WIDTH = 800;
+ WINDOW_HEIGHT = 450;
+
+ 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++ )
+ {
+#ifdef DISPLAY
+ display_title_window(connection, WINDOW_ID, argv[i]);
+#endif
+ if ( !PlayVideo(argv[i], connection) )
+ return 1;
+ }
+
+#ifdef DISPLAY
+ display_disconnect(connection);
+#else
+ dispd_destroy_window(window);
+ dispd_detach_session(session);
+#endif
+
+ return 0;
+}