From 8c65cc185a892b342816b0b31ec5da1e991a8d44 Mon Sep 17 00:00:00 2001 From: Stephan Vedder Date: Mon, 20 Nov 2023 15:05:58 +0100 Subject: [PATCH] Meta: Add a minimal SDL2 based videoplayer for Lagom --- Meta/Lagom/CMakeLists.txt | 5 + .../Contrib/VideoPlayerSDL/CMakeLists.txt | 7 ++ Meta/Lagom/Contrib/VideoPlayerSDL/main.cpp | 109 ++++++++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 Meta/Lagom/Contrib/VideoPlayerSDL/CMakeLists.txt create mode 100644 Meta/Lagom/Contrib/VideoPlayerSDL/main.cpp diff --git a/Meta/Lagom/CMakeLists.txt b/Meta/Lagom/CMakeLists.txt index 5425d89dc5..ee13f7236a 100644 --- a/Meta/Lagom/CMakeLists.txt +++ b/Meta/Lagom/CMakeLists.txt @@ -549,6 +549,11 @@ if (BUILD_LAGOM) add_serenity_subdirectory(Meta/Lagom/Contrib/MacPDF) endif() + find_package(SDL2) + if(SDL2_FOUND) + add_serenity_subdirectory(Meta/Lagom/Contrib/VideoPlayerSDL) + endif() + add_executable(icc ../../Userland/Utilities/icc.cpp) target_link_libraries(icc LibCore LibGfx LibMain) diff --git a/Meta/Lagom/Contrib/VideoPlayerSDL/CMakeLists.txt b/Meta/Lagom/Contrib/VideoPlayerSDL/CMakeLists.txt new file mode 100644 index 0000000000..540022a2b1 --- /dev/null +++ b/Meta/Lagom/Contrib/VideoPlayerSDL/CMakeLists.txt @@ -0,0 +1,7 @@ +add_compile_options(-DAK_DONT_REPLACE_STD) + +add_executable(VideoPlayerSDL + main.cpp +) + +target_link_libraries(VideoPlayerSDL PRIVATE LibMain LibCore LibGfx LibVideo SDL2::SDL2) diff --git a/Meta/Lagom/Contrib/VideoPlayerSDL/main.cpp b/Meta/Lagom/Contrib/VideoPlayerSDL/main.cpp new file mode 100644 index 0000000000..9fff3b8a8b --- /dev/null +++ b/Meta/Lagom/Contrib/VideoPlayerSDL/main.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2023, Stephan Vedder + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include +#include + +ErrorOr serenity_main(Main::Arguments arguments) +{ + StringView filename = ""sv; + Core::ArgsParser args_parser; + args_parser.add_positional_argument(filename, "The video file to display.", "filename", Core::ArgsParser::Required::No); + args_parser.parse(arguments); + + if (filename.is_empty()) { + warnln("No filename given"); + return 1; + } + + auto file = TRY(Core::File::open(filename, Core::File::OpenMode::Read)); + auto mapped_file = TRY(Core::MappedFile::map_from_file(move(file), filename)); + auto load_file_result = Video::PlaybackManager::from_mapped_file(move(mapped_file)); + if (load_file_result.is_error()) { + warnln("Failed to decode file {}", filename); + return 1; + } + + SDL_Texture* texture = NULL; + SDL_Renderer* renderer = NULL; + SDL_Window* window = NULL; + + auto playback_manager = load_file_result.release_value(); + playback_manager->on_video_frame = [&texture, &renderer, &window](RefPtr frame) { + // Delete texture if it doesn't match the frame size and resize window + if (texture != NULL) { + int width, height; + SDL_QueryTexture(texture, NULL, NULL, &width, &height); + if (width != frame->width() || height != frame->height()) { + SDL_DestroyTexture(texture); + texture = NULL; + SDL_SetWindowSize(window, frame->width(), frame->height()); + } + } + + // Create texture if it doesn't exist + if (texture == NULL) { + texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_XRGB8888, SDL_TEXTUREACCESS_STREAMING, + frame->width(), + frame->height()); + } + + u8* pixels = frame->scanline_u8(0); + int result = SDL_UpdateTexture(texture, NULL, pixels, frame->pitch()); + if (result != 0) { + warnln("Failed to update texture: {} from pixels {}", SDL_GetError(), pixels); + } + }; + + playback_manager->on_decoder_error = [](auto error) { + warnln("Decoder error: {}", error.description()); + }; + + playback_manager->on_fatal_playback_error = [](auto) { + warnln("Fatal decoder error"); + exit(1); + }; + + SDL_Init(SDL_INIT_VIDEO); + + auto& video_data = playback_manager->selected_video_track().video_data(); + window = SDL_CreateWindow( + "VideoPlayer", + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + video_data.pixel_width, + video_data.pixel_height, + 0); + + renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); + SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); + + playback_manager->resume_playback(); + + Core::EventLoop event_loop; + while (playback_manager->is_playing()) { + SDL_Event event; + if (SDL_PollEvent(&event)) { + if (event.type == SDL_QUIT) + break; + } + + event_loop.pump(Core::EventLoop::WaitMode::PollForEvents); + + SDL_RenderClear(renderer); + SDL_RenderCopy(renderer, texture, NULL, NULL); + SDL_RenderPresent(renderer); + } + + SDL_DestroyWindow(window); + SDL_Quit(); + return 0; +}