From 9b1505c5f13024f39e504f0f0949d29ce73f39e6 Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Sun, 29 Dec 2019 17:47:16 -0600 Subject: [PATCH] Windows build! --- .gitignore | 2 + singe/buildRelease.sh | 77 +++ singe/common.h | 2 +- singe/main.c | 20 +- singe/postLink.sh | 11 +- singe/preBuild.sh | 43 +- singe/singe.c | 3 +- singe/singe.h | 2 +- singe/singe.pro | 102 ++-- .../external/flac-1.3.3/doc/html/Makefile.in | 4 +- .../external/opus-1.3.1/doc/Makefile.in | 2 +- .../external/opusfile-0.11/Makefile.in | 4 +- singe/thirdparty/ffms2/include/ffms.h | 8 + .../thirdparty/ffms2/include/ffms.h.original | 455 ++++++++++++++++++ singe/util.c | 55 ++- singe/util.h | 3 +- singe/videoPlayer.c | 2 +- singe/videoPlayer.h | 2 +- 18 files changed, 705 insertions(+), 92 deletions(-) create mode 100755 singe/buildRelease.sh create mode 100644 singe/thirdparty/ffms2/include/ffms.h.original diff --git a/.gitignore b/.gitignore index 3b4246f94..43b9a4688 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,5 @@ thirdparty-build/ singe/extensions.h videotest/*.singe games/ +build/ +singe/source.inc.sh diff --git a/singe/buildRelease.sh b/singe/buildRelease.sh new file mode 100755 index 000000000..7666509a1 --- /dev/null +++ b/singe/buildRelease.sh @@ -0,0 +1,77 @@ +#!/bin/bash -e + +# +# Singe 2 +# Copyright (C) 2006-2020 Scott Duensing +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# + +source source.inc.sh + +function doBuild() { + + local TARGET=$1 + local OSNAME=$2 + local OSARCH=$3 + local EXT=$4 + local SOURCE= + local I= + local OFILES="" + local O= + + pushd "${SOURCE_DIR}/.." + mkdir -p build/${OSNAME}/${OSARCH} + cd build + if [[ -d temp ]]; then + rm -rf temp + fi + mkdir -p temp + cd temp + + for I in ${SOURCES}; do + if [[ ${I:0:1} == "/" ]]; then + SOURCE="${I}" + else + SOURCE="${SOURCE_DIR}/${I}" + fi + O=`basename ${SOURCE}` + O=${O%.*}.o + OFILES="${OFILES} ${O}" + echo "Compiling ${SOURCE}..." + ${CROSS}-gcc ${QMAKE_CFLAGS} ${EXTRA_CFLAGS} -c "${SOURCE}" -o ${O} + done + + TARGET="${SOURCE_DIR}/../build/${OSNAME}/${OSARCH}/${TARGET}${EXT}" + echo "Linking ${TARGET}..." + ${CROSS}-g++ -o "${TARGET}" ${OFILES} "-L${SOURCE_DIR}/../thirdparty-build/${OSNAME}/${OSARCH}/installed/lib" ${EXTRA_LD_FLAGS} + + echo "Compressing ${TARGET}..." + #${CROSS}-strip "${TARGET}" + #upx -9 "${TARGET}" + + popd +} + + +CROSS="x86_64-linux-gnu" +EXTRA_CFLAGS="" +EXTRA_LD_FLAGS="-l:everything.a -lpthread -lXv -lX11 -lXext -lm -ldl -lrt" +doBuild Singe-Linux-x86_64 linux 64 + +CROSS="x86_64-w64-mingw32" +EXTRA_CFLAGS="" +EXTRA_LD_FLAGS="-mwindows -static -lmingw32 -l:everything.a -lm -lbcrypt -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lsetupapi -lversion -luuid -Dmain=SDL_main" +doBuild Singe-Windows-x86_64 mingw 64 .exe diff --git a/singe/common.h b/singe/common.h index 0b9b1228c..2a650218a 100644 --- a/singe/common.h +++ b/singe/common.h @@ -1,7 +1,7 @@ /* * * Singe 2 - * Copyright (C) 2019 Scott Duensing + * Copyright (C) 2006-2020 Scott Duensing * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/singe/main.c b/singe/main.c index 7e868fb67..85f07ba5b 100644 --- a/singe/main.c +++ b/singe/main.c @@ -1,7 +1,7 @@ /* * * Singe 2 - * Copyright (C) 2019 Scott Duensing + * Copyright (C) 2006-2020 Scott Duensing * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -62,6 +62,8 @@ void showUsage(char *name, char *message); __attribute__((noreturn)) void showUsage(char *name, char *message) { + int result = 0; + utilSay(" ___ ___ _ _ ___ ___"); utilSay("/ __|_ _| \\| |/ __| __| Somewhat Interactive Nostalgic Game Emulator %s", VERSION_STRING); utilSay("\\__ \\| || .` | (_ | _| Copyright (c) 2006-%s Scott C. Duensing", COPYRIGHT_END_YEAR); @@ -91,9 +93,12 @@ void showUsage(char *name, char *message) { if (message) { utilSay("Error: %s", message); utilSay(""); - exit(1); + result = 1; } - exit(0); +#ifdef _WIN32 + getchar(); +#endif + exit(result); } @@ -163,6 +168,9 @@ int main(int argc, char *argv[]) { { { 0, 0 }, { 0, 0 } } }; + // For that dumb OS + utilRedirectConsole(); + // Parse command line while (true) { optionIndex = 0; @@ -441,7 +449,7 @@ int main(int argc, char *argv[]) { if ((_confXResolution > mode.w) || (_confYResolution > mode.h)) showUsage(argv[0], "Specified resolution is larger than the display."); // Init SDL_mixer ***FIX*** - flags = /* MIX_INIT_FLAC | */ MIX_INIT_MOD | MIX_INIT_MP3 | MIX_INIT_OGG | MIX_INIT_MID | MIX_INIT_OPUS; + flags = /* MIX_INIT_FLAC | */ MIX_INIT_MOD | /* MIX_INIT_MP3 | */ MIX_INIT_OGG | MIX_INIT_MID | MIX_INIT_OPUS; err = Mix_Init(flags); if (err != flags) utilDie("%s", Mix_GetError()); @@ -500,5 +508,9 @@ int main(int argc, char *argv[]) { if (_confScriptFile) free(_confScriptFile); utilTraceEnd(); +#ifdef _WIN32 + getchar(); +#endif + return 0; } diff --git a/singe/postLink.sh b/singe/postLink.sh index 29a157fb2..c7ce58ed8 100755 --- a/singe/postLink.sh +++ b/singe/postLink.sh @@ -2,7 +2,7 @@ # # Singe 2 -# Copyright (C) 2019 Scott Duensing +# Copyright (C) 2006-2020 Scott Duensing # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -19,8 +19,9 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # -SOURCE=$1 -TARGET=$2 +SOURCEDIR=$1 +DESTDIR=$2 +TARGET=$3 -strip "${TARGET}/singe" -upx -9 "${TARGET}/singe" +strip "${DESTDIR}/${TARGET}" +upx -9 "${DESTDIR}/${TARGET}" diff --git a/singe/preBuild.sh b/singe/preBuild.sh index ebb7b44da..526485de1 100755 --- a/singe/preBuild.sh +++ b/singe/preBuild.sh @@ -2,7 +2,7 @@ # # Singe 2 -# Copyright (C) 2019 Scott Duensing +# Copyright (C) 2006-2020 Scott Duensing # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -191,7 +191,7 @@ function outputLicense() { /* * * Singe 2 - * Copyright (C) 2019 Scott Duensing + * Copyright (C) 2006-2020 Scott Duensing * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -340,3 +340,42 @@ MODPLUG_CFLAGS="-I${G_INSTALLED}/include -DMODPLUG_STATIC" \ # === SDL2_ttf === MORE_CFLAGS="-I${G_INSTALLED}/include/SDL2" \ autoBuild libSDL2_ttf.a SDL2_ttf "--with-ft-prefix=\"${G_INSTALLED}\" --with-sdl-prefix=\"${G_INSTALLED}\"" "libSDL2_ttf.la install-libLTLIBRARIES install-libSDL2_ttfincludeHEADERS" + +# === Combine all dependencies into one big mess === +if [[ ! -e "${G_INSTALLED}/lib/everything.a" ]]; then + pushd "${G_INSTALLED}/lib" + ${G_CROSS}-ar -M <<-LIBS + CREATE everything.a + ADDLIB libSDL2main.a + ADDLIB libSDL2.a + ADDLIB libSDL2_image.a + ADDLIB libpng16.a + ADDLIB libwebp.a + ADDLIB libjpeg.a + ADDLIB libSDL2_mixer.a + ADDLIB libFLAC.a + ADDLIB libmodplug.a + ADDLIB libmpg123.a + ADDLIB libvorbisfile.a + ADDLIB libvorbis.a + ADDLIB libogg.a + ADDLIB libopusfile.a + ADDLIB libopus.a + ADDLIB libSDL2_ttf.a + ADDLIB libfreetype.a + ADDLIB libharfbuzz.a + ADDLIB liblua.a + ADDLIB libffms2.a + ADDLIB libavformat.a + ADDLIB libavcodec.a + ADDLIB libswscale.a + ADDLIB libavutil.a + ADDLIB libswresample.a + ADDLIB libz.a + ADDLIB liblzma.a + ADDLIB libbz2.a + SAVE + END + LIBS + popd +fi diff --git a/singe/singe.c b/singe/singe.c index b04ab2a24..043f6468d 100644 --- a/singe/singe.c +++ b/singe/singe.c @@ -1,7 +1,7 @@ /* * * Singe 2 - * Copyright (C) 2019 Scott Duensing + * Copyright (C) 2006-2020 Scott Duensing * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -187,7 +187,6 @@ static SpriteT *_spriteList = NULL; static SoundT *_soundList = NULL; static FontT *_fontList = NULL; static FontT *_fontCurrent = NULL; -static void *_pixelBuffer = NULL; static int _keyDefs[SWITCH_COUNT][2] = { diff --git a/singe/singe.h b/singe/singe.h index 6692093be..9cd4f31f3 100644 --- a/singe/singe.h +++ b/singe/singe.h @@ -1,7 +1,7 @@ /* * * Singe 2 - * Copyright (C) 2019 Scott Duensing + * Copyright (C) 2006-2020 Scott Duensing * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/singe/singe.pro b/singe/singe.pro index ca42ad291..97e488611 100644 --- a/singe/singe.pro +++ b/singe/singe.pro @@ -1,6 +1,6 @@ # # Singe 2 -# Copyright (C) 2019 Scott Duensing +# Copyright (C) 2006-2020 Scott Duensing # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -17,53 +17,36 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # -TARGET = singeEmu - # We're just a boring old C app + TEMPLATE = app CONFIG += console CONFIG -= app_bundle CONFIG -= qt -# Keep binaries to themselves -DESTDIR = $$OUT_PWD/build +# Target Settings -# Make Visual C shut up about stupidness -win32 { - DEFINES *= \ - _CRT_SECURE_NO_WARNINGS \ - _CRT_NONSTDC_NO_DEPRECATE - MSVC_VER = $$(VisualStudioVersion) - if(equals(MSVC_VER, 14.0)|greaterThan(MSVC_VER, 14.0)) { - message("Timespec is defined") - DEFINES *= HAVE_STRUCT_TIMESPEC - } -} - -# Determine Bitness - This is just broken -win32 { - contains(QMAKE_HOST.arch, x86_64) { - CONFIG *= bits64 - } else { - CONFIG *= bits32 - } -} else { - *-64 | *_64 { - CONFIG *= bits64 - } else { - CONFIG *= bits32 - } -} -BITNESS="64" -bits32:BITNESS="32" -# HACK HACK HACK due to above -BITNESS="64" -CONFIG -= bits32 +TARGET = singeEmu +CONFIG += platformLinux CONFIG += bits64 +# Keep binaries to themselves + +DESTDIR = $$OUT_PWD/build + # === Third Party Builds === -BUILDTHIRDARGS = \"$$PWD/thirdparty\" \"$$OUT_PWD/../thirdparty-build\" $$BITNESS +bits64 { + BITNESS="64" +} else { + BITNESS="32" +} +platformLinux { + PLATFORM="linux" +} else { + PLATFORM="mingw" +} +BUILDTHIRDARGS = \"$$PWD/thirdparty\" \"$$OUT_PWD/../thirdparty-build\" $$BITNESS $$PLATFORM win32 { # Placeholder - doesn't work BUILDTHIRD.commands = cmd.exe /c $$PWD\\preBuild.bat $$BUILDTHIRDARGS @@ -94,7 +77,7 @@ MANYMOUSE_SOURCES = \ QMAKE_CFLAGS += \ -isystem $$MANYMOUSE_INCLUDES \ - -isystem $$PWD/../thirdparty-build/$$BITNESS/installed/include + -isystem $$PWD/../thirdparty-build/$$PLATFORM/$$BITNESS/installed/include HEADERS += \ $$MANYMOUSE_HEADERS \ @@ -114,34 +97,8 @@ SOURCES += \ main.c LIBS += \ - -L$$PWD/../thirdparty-build/$$BITNESS/installed/lib \ - -l:libSDL2.a \ - -l:libSDL2_image.a \ - -l:libpng16.a \ - -l:libwebp.a \ - -l:libjpeg.a \ - -l:libSDL2_mixer.a \ - -l:libFLAC.a \ - -l:libmodplug.a \ - -l:libmpg123.a \ - -l:libvorbisfile.a \ - -l:libvorbis.a \ - -l:libogg.a \ - -l:libopusfile.a \ - -l:libopus.a \ - -l:libSDL2_ttf.a \ - -l:libfreetype.a \ - -l:libharfbuzz.a \ - -l:liblua.a \ - -l:libffms2.a \ - -l:libavformat.a \ - -l:libavcodec.a \ - -l:libswscale.a \ - -l:libavutil.a \ - -l:libswresample.a \ - -l:libz.a \ - -l:liblzma.a \ - -l:libbz2.a \ + -L$$PWD/../thirdparty-build/$$PLATFORM/$$BITNESS/installed/lib \ + -l:everything.a \ -lpthread \ -lXv \ -lX11 \ @@ -152,7 +109,16 @@ LIBS += \ OTHER_FILES += \ preBuild.sh \ - postLink.sh + postLink.sh \ + buildRelease.sh + +FILEINFO = "SOURCES=\"$$SOURCES\"" \ + "HEADERS=\"$$HEADERS\"" \ + "LINUX_LIBS=\"$$LIBS\"" \ + "SOURCE_DIR=\"$$PWD\"" \ + "QMAKE_CFLAGS=\"$$QMAKE_CFLAGS\"" + +write_file("source.inc.sh", FILEINFO) # Strip & UPX the final result -#linux:QMAKE_POST_LINK += bash $$PWD/postLink.sh "$$PWD" "$$DESTDIR" +#linux:QMAKE_POST_LINK += bash $$PWD/postLink.sh "$$PWD" "$$DESTDIR" "$$TARGET" diff --git a/singe/thirdparty/SDL2_mixer/external/flac-1.3.3/doc/html/Makefile.in b/singe/thirdparty/SDL2_mixer/external/flac-1.3.3/doc/html/Makefile.in index 481fee20c..65de627fd 100644 --- a/singe/thirdparty/SDL2_mixer/external/flac-1.3.3/doc/html/Makefile.in +++ b/singe/thirdparty/SDL2_mixer/external/flac-1.3.3/doc/html/Makefile.in @@ -667,9 +667,9 @@ distclean-generic: maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -@FLaC__HAS_DOXYGEN_FALSE@uninstall-local: -@FLaC__HAS_DOXYGEN_FALSE@distclean-local: @FLaC__HAS_DOXYGEN_FALSE@install-data-local: +@FLaC__HAS_DOXYGEN_FALSE@distclean-local: +@FLaC__HAS_DOXYGEN_FALSE@uninstall-local: clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am diff --git a/singe/thirdparty/SDL2_mixer/external/opus-1.3.1/doc/Makefile.in b/singe/thirdparty/SDL2_mixer/external/opus-1.3.1/doc/Makefile.in index 354da2ad2..cae040bf9 100644 --- a/singe/thirdparty/SDL2_mixer/external/opus-1.3.1/doc/Makefile.in +++ b/singe/thirdparty/SDL2_mixer/external/opus-1.3.1/doc/Makefile.in @@ -394,9 +394,9 @@ distclean-generic: maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." +@HAVE_DOXYGEN_FALSE@clean-local: @HAVE_DOXYGEN_FALSE@uninstall-local: @HAVE_DOXYGEN_FALSE@install-data-local: -@HAVE_DOXYGEN_FALSE@clean-local: clean: clean-am clean-am: clean-generic clean-libtool clean-local mostlyclean-am diff --git a/singe/thirdparty/SDL2_mixer/external/opusfile-0.11/Makefile.in b/singe/thirdparty/SDL2_mixer/external/opusfile-0.11/Makefile.in index 721283f8d..2ce5de6c0 100644 --- a/singe/thirdparty/SDL2_mixer/external/opusfile-0.11/Makefile.in +++ b/singe/thirdparty/SDL2_mixer/external/opusfile-0.11/Makefile.in @@ -1018,9 +1018,9 @@ distclean-generic: maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -@HAVE_DOXYGEN_FALSE@install-data-local: -@HAVE_DOXYGEN_FALSE@uninstall-local: @HAVE_DOXYGEN_FALSE@clean-local: +@HAVE_DOXYGEN_FALSE@uninstall-local: +@HAVE_DOXYGEN_FALSE@install-data-local: clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool clean-local \ diff --git a/singe/thirdparty/ffms2/include/ffms.h b/singe/thirdparty/ffms2/include/ffms.h index d8c5a9713..9a49a2f5f 100644 --- a/singe/thirdparty/ffms2/include/ffms.h +++ b/singe/thirdparty/ffms2/include/ffms.h @@ -65,23 +65,31 @@ #endif // And now for some symbol hide-and-seek... +/* #if defined(_WIN32) && !defined(FFMS_STATIC) // MSVC # if defined(FFMS_EXPORTS) // building the FFMS2 library itself, with visible API symbols # define FFMS_API(ret) FFMS_EXTERN_C __declspec(dllexport) ret FFMS_CC # define FFMS_DEPRECATED_API(ret) FFMS_EXTERN_C FFMS_DEPRECATED __declspec(dllexport) ret FFMS_CC +#error Boom 1 # else // building something that depends on FFMS2 # define FFMS_API(ret) FFMS_EXTERN_C __declspec(dllimport) ret FFMS_CC # define FFMS_DEPRECATED_API(ret) FFMS_EXTERN_C FFMS_DEPRECATED __declspec(dllimport) ret FFMS_CC +#error Boom 2 # endif // defined(FFMS_EXPORTS) // GCC 4 or later: export API symbols only. Some GCC 3.x versions support the visibility attribute too, // but we don't really care enough about that to add compatibility defines for it. #elif defined(__GNUC__) && __GNUC__ >= 4 +*/ # define FFMS_API(ret) FFMS_EXTERN_C __attribute__((visibility("default"))) ret FFMS_CC # define FFMS_DEPRECATED_API(ret) FFMS_EXTERN_C FFMS_DEPRECATED __attribute__((visibility("default"))) ret FFMS_CC +/* +#error Boom 3 #else // fallback for everything else # define FFMS_API(ret) FFMS_EXTERN_C ret FFMS_CC # define FFMS_DEPRECATED_API(ret) FFMS_EXTERN_C FFMS_DEPRECATED ret FFMS_CC +#error Boom 4 #endif // defined(_MSC_VER) +*/ // we now return you to your regularly scheduled programming. diff --git a/singe/thirdparty/ffms2/include/ffms.h.original b/singe/thirdparty/ffms2/include/ffms.h.original new file mode 100644 index 000000000..d8c5a9713 --- /dev/null +++ b/singe/thirdparty/ffms2/include/ffms.h.original @@ -0,0 +1,455 @@ +// Copyright (c) 2007-2018 Fredrik Mellbin +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef FFMS_H +#define FFMS_H + +// Version format: major - minor - micro - bump +#define FFMS_VERSION ((2 << 24) | (31 << 16) | (0 << 8) | 0) + +#include +#include + + +/******** +* The following preprocessor voodoo ensures that all API symbols are exported +* as intended on all supported platforms, that non-API symbols are hidden (where possible), +* and that the correct calling convention and extern declarations are used. +* The end result should be that linking to FFMS2 Just Works. +********/ + +// Convenience for C++ users. +#if defined(__cplusplus) +# define FFMS_EXTERN_C extern "C" +#else +# define FFMS_EXTERN_C +#endif + +// On win32, we need to ensure we use stdcall with all compilers. +#if defined(_WIN32) && !defined(_WIN64) +# define FFMS_CC __stdcall +#else +# define FFMS_CC +#endif + +// compiler-specific deprecation attributes +#ifndef FFMS_EXPORTS +# if defined(__GNUC__) && (__GNUC__ >= 4) +# define FFMS_DEPRECATED __attribute__((deprecated)) +# elif defined(_MSC_VER) +# define FFMS_DEPRECATED __declspec(deprecated) +# endif +#endif + +#ifndef FFMS_DEPRECATED +// Define as empty if the compiler doesn't support deprecation attributes or +// if we're building FFMS2 itself +# define FFMS_DEPRECATED +#endif + +// And now for some symbol hide-and-seek... +#if defined(_WIN32) && !defined(FFMS_STATIC) // MSVC +# if defined(FFMS_EXPORTS) // building the FFMS2 library itself, with visible API symbols +# define FFMS_API(ret) FFMS_EXTERN_C __declspec(dllexport) ret FFMS_CC +# define FFMS_DEPRECATED_API(ret) FFMS_EXTERN_C FFMS_DEPRECATED __declspec(dllexport) ret FFMS_CC +# else // building something that depends on FFMS2 +# define FFMS_API(ret) FFMS_EXTERN_C __declspec(dllimport) ret FFMS_CC +# define FFMS_DEPRECATED_API(ret) FFMS_EXTERN_C FFMS_DEPRECATED __declspec(dllimport) ret FFMS_CC +# endif // defined(FFMS_EXPORTS) +// GCC 4 or later: export API symbols only. Some GCC 3.x versions support the visibility attribute too, +// but we don't really care enough about that to add compatibility defines for it. +#elif defined(__GNUC__) && __GNUC__ >= 4 +# define FFMS_API(ret) FFMS_EXTERN_C __attribute__((visibility("default"))) ret FFMS_CC +# define FFMS_DEPRECATED_API(ret) FFMS_EXTERN_C FFMS_DEPRECATED __attribute__((visibility("default"))) ret FFMS_CC +#else // fallback for everything else +# define FFMS_API(ret) FFMS_EXTERN_C ret FFMS_CC +# define FFMS_DEPRECATED_API(ret) FFMS_EXTERN_C FFMS_DEPRECATED ret FFMS_CC +#endif // defined(_MSC_VER) + + +// we now return you to your regularly scheduled programming. + +typedef struct FFMS_ErrorInfo { + int ErrorType; + int SubType; + int BufferSize; + char *Buffer; +} FFMS_ErrorInfo; + +typedef struct FFMS_VideoSource FFMS_VideoSource; +typedef struct FFMS_AudioSource FFMS_AudioSource; +typedef struct FFMS_Indexer FFMS_Indexer; +typedef struct FFMS_Index FFMS_Index; +typedef struct FFMS_Track FFMS_Track; + +typedef enum FFMS_Errors { + // No error + FFMS_ERROR_SUCCESS = 0, + + // Main types - where the error occurred + FFMS_ERROR_INDEX = 1, // index file handling + FFMS_ERROR_INDEXING, // indexing + FFMS_ERROR_POSTPROCESSING, // video postprocessing (libpostproc) + FFMS_ERROR_SCALING, // image scaling (libswscale) + FFMS_ERROR_DECODING, // audio/video decoding + FFMS_ERROR_SEEKING, // seeking + FFMS_ERROR_PARSER, // file parsing + FFMS_ERROR_TRACK, // track handling + FFMS_ERROR_WAVE_WRITER, // WAVE64 file writer + FFMS_ERROR_CANCELLED, // operation aborted + FFMS_ERROR_RESAMPLING, // audio resampling (libavresample) + + // Subtypes - what caused the error + FFMS_ERROR_UNKNOWN = 20, // unknown error + FFMS_ERROR_UNSUPPORTED, // format or operation is not supported with this binary + FFMS_ERROR_FILE_READ, // cannot read from file + FFMS_ERROR_FILE_WRITE, // cannot write to file + FFMS_ERROR_NO_FILE, // no such file or directory + FFMS_ERROR_VERSION, // wrong version + FFMS_ERROR_ALLOCATION_FAILED, // out of memory + FFMS_ERROR_INVALID_ARGUMENT, // invalid or nonsensical argument + FFMS_ERROR_CODEC, // decoder error + FFMS_ERROR_NOT_AVAILABLE, // requested mode or operation unavailable in this binary + FFMS_ERROR_FILE_MISMATCH, // provided index does not match the file + FFMS_ERROR_USER // problem exists between keyboard and chair +} FFMS_Errors; + +typedef enum FFMS_SeekMode { + FFMS_SEEK_LINEAR_NO_RW = -1, + FFMS_SEEK_LINEAR = 0, + FFMS_SEEK_NORMAL = 1, + FFMS_SEEK_UNSAFE = 2, + FFMS_SEEK_AGGRESSIVE = 3 +} FFMS_SeekMode; + +typedef enum FFMS_IndexErrorHandling { + FFMS_IEH_ABORT = 0, + FFMS_IEH_CLEAR_TRACK = 1, + FFMS_IEH_STOP_TRACK = 2, + FFMS_IEH_IGNORE = 3 +} FFMS_IndexErrorHandling; + +typedef enum FFMS_TrackType { + FFMS_TYPE_UNKNOWN = -1, + FFMS_TYPE_VIDEO, + FFMS_TYPE_AUDIO, + FFMS_TYPE_DATA, + FFMS_TYPE_SUBTITLE, + FFMS_TYPE_ATTACHMENT +} FFMS_TrackType; + +typedef enum FFMS_SampleFormat { + FFMS_FMT_U8 = 0, + FFMS_FMT_S16, + FFMS_FMT_S32, + FFMS_FMT_FLT, + FFMS_FMT_DBL +} FFMS_SampleFormat; + +typedef enum FFMS_AudioChannel { + FFMS_CH_FRONT_LEFT = 0x00000001, + FFMS_CH_FRONT_RIGHT = 0x00000002, + FFMS_CH_FRONT_CENTER = 0x00000004, + FFMS_CH_LOW_FREQUENCY = 0x00000008, + FFMS_CH_BACK_LEFT = 0x00000010, + FFMS_CH_BACK_RIGHT = 0x00000020, + FFMS_CH_FRONT_LEFT_OF_CENTER = 0x00000040, + FFMS_CH_FRONT_RIGHT_OF_CENTER = 0x00000080, + FFMS_CH_BACK_CENTER = 0x00000100, + FFMS_CH_SIDE_LEFT = 0x00000200, + FFMS_CH_SIDE_RIGHT = 0x00000400, + FFMS_CH_TOP_CENTER = 0x00000800, + FFMS_CH_TOP_FRONT_LEFT = 0x00001000, + FFMS_CH_TOP_FRONT_CENTER = 0x00002000, + FFMS_CH_TOP_FRONT_RIGHT = 0x00004000, + FFMS_CH_TOP_BACK_LEFT = 0x00008000, + FFMS_CH_TOP_BACK_CENTER = 0x00010000, + FFMS_CH_TOP_BACK_RIGHT = 0x00020000, + FFMS_CH_STEREO_LEFT = 0x20000000, + FFMS_CH_STEREO_RIGHT = 0x40000000 +} FFMS_AudioChannel; + +typedef enum FFMS_Resizers { + FFMS_RESIZER_FAST_BILINEAR = 0x0001, + FFMS_RESIZER_BILINEAR = 0x0002, + FFMS_RESIZER_BICUBIC = 0x0004, + FFMS_RESIZER_X = 0x0008, + FFMS_RESIZER_POINT = 0x0010, + FFMS_RESIZER_AREA = 0x0020, + FFMS_RESIZER_BICUBLIN = 0x0040, + FFMS_RESIZER_GAUSS = 0x0080, + FFMS_RESIZER_SINC = 0x0100, + FFMS_RESIZER_LANCZOS = 0x0200, + FFMS_RESIZER_SPLINE = 0x0400 +} FFMS_Resizers; + +typedef enum FFMS_AudioDelayModes { + FFMS_DELAY_NO_SHIFT = -3, + FFMS_DELAY_TIME_ZERO = -2, + FFMS_DELAY_FIRST_VIDEO_TRACK = -1 +} FFMS_AudioDelayModes; + +typedef enum FFMS_ChromaLocations { + FFMS_LOC_UNSPECIFIED = 0, + FFMS_LOC_LEFT = 1, + FFMS_LOC_CENTER = 2, + FFMS_LOC_TOPLEFT = 3, + FFMS_LOC_TOP = 4, + FFMS_LOC_BOTTOMLEFT = 5, + FFMS_LOC_BOTTOM = 6 +} FFMS_ChromaLocations; + +typedef enum FFMS_ColorRanges { + FFMS_CR_UNSPECIFIED = 0, + FFMS_CR_MPEG = 1, // 219*2^(n-8), i.e. 16-235 with 8-bit samples + FFMS_CR_JPEG = 2 // 2^n-1, or "fullrange" +} FFMS_ColorRanges; + +typedef enum FFMS_Stereo3DType { + FFMS_S3D_TYPE_2D = 0, + FFMS_S3D_TYPE_SIDEBYSIDE, + FFMS_S3D_TYPE_TOPBOTTOM, + FFMS_S3D_TYPE_FRAMESEQUENCE, + FFMS_S3D_TYPE_CHECKERBOARD, + FFMS_S3D_TYPE_SIDEBYSIDE_QUINCUNX, + FFMS_S3D_TYPE_LINES, + FFMS_S3D_TYPE_COLUMNS +} FFMS_Stereo3DType; + +typedef enum FFMS_Stereo3DFlags { + FFMS_S3D_FLAGS_INVERT = 1 +} FFMS_Stereo3DFlags; + +typedef enum FFMS_MixingCoefficientType { + FFMS_MIXING_COEFFICIENT_Q8 = 0, + FFMS_MIXING_COEFFICIENT_Q15 = 1, + FFMS_MIXING_COEFFICIENT_FLT = 2 +} FFMS_MixingCoefficientType; + +typedef enum FFMS_MatrixEncoding { + FFMS_MATRIX_ENCODING_NONE = 0, + FFMS_MATRIX_ENCODING_DOBLY = 1, + FFMS_MATRIX_ENCODING_PRO_LOGIC_II = 2, + FFMS_MATRIX_ENCODING_PRO_LOGIC_IIX = 3, + FFMS_MATRIX_ENCODING_PRO_LOGIC_IIZ = 4, + FFMS_MATRIX_ENCODING_DOLBY_EX = 5, + FFMS_MATRIX_ENCODING_DOLBY_HEADPHONE = 6 +} FFMS_MatrixEncoding; + +typedef enum FFMS_ResampleFilterType { + FFMS_RESAMPLE_FILTER_CUBIC = 0, + FFMS_RESAMPLE_FILTER_SINC = 1, /* misnamed as multiple windowsed sinc filters exist, actually called BLACKMAN_NUTTALL */ + FFMS_RESAMPLE_FILTER_KAISER = 2 +} FFMS_ResampleFilterType; + +typedef enum FFMS_AudioDitherMethod { + FFMS_RESAMPLE_DITHER_NONE = 0, + FFMS_RESAMPLE_DITHER_RECTANGULAR = 1, + FFMS_RESAMPLE_DITHER_TRIANGULAR = 2, + FFMS_RESAMPLE_DITHER_TRIANGULAR_HIGHPASS = 3, + FFMS_RESAMPLE_DITHER_TRIANGULAR_NOISESHAPING = 4 +} FFMS_AudioDitherMethod; + +typedef enum FFMS_LogLevels { + FFMS_LOG_QUIET = -8, + FFMS_LOG_PANIC = 0, + FFMS_LOG_FATAL = 8, + FFMS_LOG_ERROR = 16, + FFMS_LOG_WARNING = 24, + FFMS_LOG_INFO = 32, + FFMS_LOG_VERBOSE = 40, + FFMS_LOG_DEBUG = 48, + FFMS_LOG_TRACE = 56 +} FFMS_LogLevels; + +typedef struct FFMS_ResampleOptions { + int64_t ChannelLayout; + FFMS_SampleFormat SampleFormat; + int SampleRate; + FFMS_MixingCoefficientType MixingCoefficientType; + double CenterMixLevel; + double SurroundMixLevel; + double LFEMixLevel; + int Normalize; + int ForceResample; + int ResampleFilterSize; + int ResamplePhaseShift; + int LinearInterpolation; + double CutoffFrequencyRatio; + FFMS_MatrixEncoding MatrixedStereoEncoding; + FFMS_ResampleFilterType FilterType; + int KaiserBeta; + FFMS_AudioDitherMethod DitherMethod; +} FFMS_ResampleOptions; + + +typedef struct FFMS_Frame { + const uint8_t *Data[4]; + int Linesize[4]; + int EncodedWidth; + int EncodedHeight; + int EncodedPixelFormat; + int ScaledWidth; + int ScaledHeight; + int ConvertedPixelFormat; + int KeyFrame; + int RepeatPict; + int InterlacedFrame; + int TopFieldFirst; + char PictType; + int ColorSpace; + int ColorRange; + /* Introduced in FFMS_VERSION ((2 << 24) | (21 << 16) | (0 << 8) | 0) */ + int ColorPrimaries; + int TransferCharateristics; + int ChromaLocation; + /* Introduced in FFMS_VERSION ((2 << 24) | (27 << 16) | (0 << 8) | 0) */ + int HasMasteringDisplayPrimaries; /* Non-zero if the 4 fields below are valid */ + double MasteringDisplayPrimariesX[3]; + double MasteringDisplayPrimariesY[3]; + double MasteringDisplayWhitePointX; + double MasteringDisplayWhitePointY; + int HasMasteringDisplayLuminance; /* Non-zero if the 2 fields below are valid */ + double MasteringDisplayMinLuminance; + double MasteringDisplayMaxLuminance; + int HasContentLightLevel; /* Non-zero if the 2 fields below are valid */ + unsigned int ContentLightLevelMax; + unsigned int ContentLightLevelAverage; +} FFMS_Frame; + +typedef struct FFMS_TrackTimeBase { + int64_t Num; + int64_t Den; +} FFMS_TrackTimeBase; + +typedef struct FFMS_FrameInfo { + int64_t PTS; + int RepeatPict; + int KeyFrame; + int64_t OriginalPTS; +} FFMS_FrameInfo; + +typedef struct FFMS_VideoProperties { + int FPSDenominator; + int FPSNumerator; + int RFFDenominator; + int RFFNumerator; + int NumFrames; + int SARNum; + int SARDen; + int CropTop; + int CropBottom; + int CropLeft; + int CropRight; + int TopFieldFirst; + FFMS_DEPRECATED int ColorSpace; /* Provided in FFMS_Frame */ + FFMS_DEPRECATED int ColorRange; /* Provided in FFMS_Frame */ + double FirstTime; + double LastTime; + /* Introduced in FFMS_VERSION ((2 << 24) | (24 << 16) | (0 << 8) | 0) */ + int Rotation; + int Stereo3DType; + int Stereo3DFlags; + /* Introduced in FFMS_VERSION ((2 << 24) | (30 << 16) | (0 << 8) | 0) */ + double LastEndTime; + int HasMasteringDisplayPrimaries; /* Non-zero if the 4 fields below are valid */ + double MasteringDisplayPrimariesX[3]; + double MasteringDisplayPrimariesY[3]; + double MasteringDisplayWhitePointX; + double MasteringDisplayWhitePointY; + int HasMasteringDisplayLuminance; /* Non-zero if the 2 fields below are valid */ + double MasteringDisplayMinLuminance; + double MasteringDisplayMaxLuminance; + int HasContentLightLevel; /* Non-zero if the 2 fields below are valid */ + unsigned int ContentLightLevelMax; + unsigned int ContentLightLevelAverage; + /* Introduced in FFMS_VERSION ((2 << 24) | (31 << 16) | (0 << 8) | 0) */ + int Flip; +} FFMS_VideoProperties; + +typedef struct FFMS_AudioProperties { + int SampleFormat; + int SampleRate; + int BitsPerSample; + int Channels; + int64_t ChannelLayout; // should probably be a plain int, none of the constants are >32 bits long + int64_t NumSamples; + double FirstTime; + double LastTime; + /* Introduced in FFMS_VERSION ((2 << 24) | (30 << 16) | (0 << 8) | 0) */ + double LastEndTime; +} FFMS_AudioProperties; + +typedef int (FFMS_CC *TIndexCallback)(int64_t Current, int64_t Total, void *ICPrivate); + +/* Most functions return 0 on success */ +/* Functions without error message output can be assumed to never fail in a graceful way */ +FFMS_API(void) FFMS_Init(int, int); /* Pass 0 to both arguments, kept to partially preserve abi */ +FFMS_API(void) FFMS_Deinit(); +FFMS_API(int) FFMS_GetVersion(); +FFMS_API(int) FFMS_GetLogLevel(); +FFMS_API(void) FFMS_SetLogLevel(int Level); +FFMS_API(FFMS_VideoSource *) FFMS_CreateVideoSource(const char *SourceFile, int Track, FFMS_Index *Index, int Threads, int SeekMode, FFMS_ErrorInfo *ErrorInfo); +FFMS_API(FFMS_AudioSource *) FFMS_CreateAudioSource(const char *SourceFile, int Track, FFMS_Index *Index, int DelayMode, FFMS_ErrorInfo *ErrorInfo); +FFMS_API(void) FFMS_DestroyVideoSource(FFMS_VideoSource *V); +FFMS_API(void) FFMS_DestroyAudioSource(FFMS_AudioSource *A); +FFMS_API(const FFMS_VideoProperties *) FFMS_GetVideoProperties(FFMS_VideoSource *V); +FFMS_API(const FFMS_AudioProperties *) FFMS_GetAudioProperties(FFMS_AudioSource *A); +FFMS_API(const FFMS_Frame *) FFMS_GetFrame(FFMS_VideoSource *V, int n, FFMS_ErrorInfo *ErrorInfo); +FFMS_API(const FFMS_Frame *) FFMS_GetFrameByTime(FFMS_VideoSource *V, double Time, FFMS_ErrorInfo *ErrorInfo); +FFMS_API(int) FFMS_GetAudio(FFMS_AudioSource *A, void *Buf, int64_t Start, int64_t Count, FFMS_ErrorInfo *ErrorInfo); +FFMS_API(int) FFMS_SetOutputFormatV2(FFMS_VideoSource *V, const int *TargetFormats, int Width, int Height, int Resizer, FFMS_ErrorInfo *ErrorInfo); /* Introduced in FFMS_VERSION ((2 << 24) | (15 << 16) | (3 << 8) | 0) */ +FFMS_API(void) FFMS_ResetOutputFormatV(FFMS_VideoSource *V); +FFMS_API(int) FFMS_SetInputFormatV(FFMS_VideoSource *V, int ColorSpace, int ColorRange, int Format, FFMS_ErrorInfo *ErrorInfo); /* Introduced in FFMS_VERSION ((2 << 24) | (17 << 16) | (1 << 8) | 0) */ +FFMS_API(void) FFMS_ResetInputFormatV(FFMS_VideoSource *V); +FFMS_API(FFMS_ResampleOptions *) FFMS_CreateResampleOptions(FFMS_AudioSource *A); /* Introduced in FFMS_VERSION ((2 << 24) | (15 << 16) | (4 << 8) | 0) */ +FFMS_API(int) FFMS_SetOutputFormatA(FFMS_AudioSource *A, const FFMS_ResampleOptions*options, FFMS_ErrorInfo *ErrorInfo); /* Introduced in FFMS_VERSION ((2 << 24) | (15 << 16) | (4 << 8) | 0) */ +FFMS_API(void) FFMS_DestroyResampleOptions(FFMS_ResampleOptions *options); /* Introduced in FFMS_VERSION ((2 << 24) | (15 << 16) | (4 << 8) | 0) */ +FFMS_API(void) FFMS_DestroyIndex(FFMS_Index *Index); +FFMS_API(int) FFMS_GetFirstTrackOfType(FFMS_Index *Index, int TrackType, FFMS_ErrorInfo *ErrorInfo); +FFMS_API(int) FFMS_GetFirstIndexedTrackOfType(FFMS_Index *Index, int TrackType, FFMS_ErrorInfo *ErrorInfo); +FFMS_API(int) FFMS_GetNumTracks(FFMS_Index *Index); +FFMS_API(int) FFMS_GetNumTracksI(FFMS_Indexer *Indexer); +FFMS_API(int) FFMS_GetTrackType(FFMS_Track *T); +FFMS_API(int) FFMS_GetTrackTypeI(FFMS_Indexer *Indexer, int Track); +FFMS_API(FFMS_IndexErrorHandling) FFMS_GetErrorHandling(FFMS_Index *Index); +FFMS_API(const char *) FFMS_GetCodecNameI(FFMS_Indexer *Indexer, int Track); +FFMS_API(const char *) FFMS_GetFormatNameI(FFMS_Indexer *Indexer); +FFMS_API(int) FFMS_GetNumFrames(FFMS_Track *T); +FFMS_API(const FFMS_FrameInfo *) FFMS_GetFrameInfo(FFMS_Track *T, int Frame); +FFMS_API(FFMS_Track *) FFMS_GetTrackFromIndex(FFMS_Index *Index, int Track); +FFMS_API(FFMS_Track *) FFMS_GetTrackFromVideo(FFMS_VideoSource *V); +FFMS_API(FFMS_Track *) FFMS_GetTrackFromAudio(FFMS_AudioSource *A); +FFMS_API(const FFMS_TrackTimeBase *) FFMS_GetTimeBase(FFMS_Track *T); +FFMS_API(int) FFMS_WriteTimecodes(FFMS_Track *T, const char *TimecodeFile, FFMS_ErrorInfo *ErrorInfo); +FFMS_API(FFMS_Indexer *) FFMS_CreateIndexer(const char *SourceFile, FFMS_ErrorInfo *ErrorInfo); +FFMS_API(void) FFMS_TrackIndexSettings(FFMS_Indexer *Indexer, int Track, int Index, int); /* Pass 0 to last argument, kapt to preserve abi. Introduced in FFMS_VERSION ((2 << 24) | (21 << 16) | (0 << 8) | 0) */ +FFMS_API(void) FFMS_TrackTypeIndexSettings(FFMS_Indexer *Indexer, int TrackType, int Index, int); /* Pass 0 to last argument, kapt to preserve abi. Introduced in FFMS_VERSION ((2 << 24) | (21 << 16) | (0 << 8) | 0) */ +FFMS_API(void) FFMS_SetProgressCallback(FFMS_Indexer *Indexer, TIndexCallback IC, void *ICPrivate); /* Introduced in FFMS_VERSION ((2 << 24) | (21 << 16) | (0 << 8) | 0) */ +FFMS_API(FFMS_Index *) FFMS_DoIndexing2(FFMS_Indexer *Indexer, int ErrorHandling, FFMS_ErrorInfo *ErrorInfo); /* Introduced in FFMS_VERSION ((2 << 24) | (21 << 16) | (0 << 8) | 0) */ +FFMS_API(void) FFMS_CancelIndexing(FFMS_Indexer *Indexer); +FFMS_API(FFMS_Index *) FFMS_ReadIndex(const char *IndexFile, FFMS_ErrorInfo *ErrorInfo); +FFMS_API(FFMS_Index *) FFMS_ReadIndexFromBuffer(const uint8_t *Buffer, size_t Size, FFMS_ErrorInfo *ErrorInfo); +FFMS_API(int) FFMS_IndexBelongsToFile(FFMS_Index *Index, const char *SourceFile, FFMS_ErrorInfo *ErrorInfo); +FFMS_API(int) FFMS_WriteIndex(const char *IndexFile, FFMS_Index *Index, FFMS_ErrorInfo *ErrorInfo); +FFMS_API(int) FFMS_WriteIndexToBuffer(uint8_t **BufferPtr, size_t *Size, FFMS_Index *Index, FFMS_ErrorInfo *ErrorInfo); +FFMS_API(void) FFMS_FreeIndexBuffer(uint8_t **BufferPtr); +FFMS_API(int) FFMS_GetPixFmt(const char *Name); +#endif diff --git a/singe/util.c b/singe/util.c index 21601cbba..12f22c80c 100644 --- a/singe/util.c +++ b/singe/util.c @@ -1,7 +1,7 @@ /* * * Singe 2 - * Copyright (C) 2019 Scott Duensing + * Copyright (C) 2006-2020 Scott Duensing * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -20,6 +20,16 @@ */ +#ifdef _WIN32 +#include +#include +#include +#include + +static const int CONSOLE_LINES = 1000; +#endif + + #include #include #include @@ -69,6 +79,9 @@ void utilDie(char *fmt, ...) { va_end(args); printf("\n"); fflush(stderr); +#ifdef _WIN32 + getchar(); +#endif exit(1); } @@ -136,6 +149,46 @@ bool utilPathExists(char *pathname) { } +void utilRedirectConsole(void) { +#ifdef _WIN32 + // http://dslweb.nwnexus.com/~ast/dload/guicon.htm + int hConHandle; + intptr_t lStdHandle; + CONSOLE_SCREEN_BUFFER_INFO coninfo; + FILE *fp; + + // allocate a console for this app + AllocConsole(); + + // set the screen buffer to be big enough to let us scroll text + GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo); + coninfo.dwSize.Y = CONSOLE_LINES; + SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize); + + // redirect unbuffered STDOUT to the console + lStdHandle = (intptr_t)GetStdHandle(STD_OUTPUT_HANDLE); + hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); + fp = _fdopen(hConHandle, "w"); + *stdout = *fp; + setvbuf(stdout, NULL, _IONBF, 0); + + // redirect unbuffered STDIN to the console + lStdHandle = (intptr_t)GetStdHandle(STD_INPUT_HANDLE); + hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); + fp = _fdopen(hConHandle, "r"); + *stdin = *fp; + setvbuf(stdin, NULL, _IONBF, 0); + + // redirect unbuffered STDERR to the console + lStdHandle = (intptr_t)GetStdHandle(STD_ERROR_HANDLE); + hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); + fp = _fdopen(hConHandle, "w"); + *stderr = *fp; + setvbuf(stderr, NULL, _IONBF, 0); +#endif +} + + __attribute__((__format__(__printf__, 1, 0))) void utilSay(char *fmt, ...) { va_list args; diff --git a/singe/util.h b/singe/util.h index 8feb4466a..8adaf3e9a 100644 --- a/singe/util.h +++ b/singe/util.h @@ -1,7 +1,7 @@ /* * * Singe 2 - * Copyright (C) 2019 Scott Duensing + * Copyright (C) 2006-2020 Scott Duensing * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -42,6 +42,7 @@ char *utilGetFileExtension(char *filename); char *utilGetLastPathComponent(char *pathname); char utilGetPathSeparator(void); bool utilPathExists(char *pathname); +void utilRedirectConsole(void); void utilSay(char *fmt, ...); void utilTrace(char *fmt, ...); void utilTraceEnd(void); diff --git a/singe/videoPlayer.c b/singe/videoPlayer.c index e14f72f05..85020f8d7 100644 --- a/singe/videoPlayer.c +++ b/singe/videoPlayer.c @@ -1,7 +1,7 @@ /* * * Singe 2 - * Copyright (C) 2019 Scott Duensing + * Copyright (C) 2006-2020 Scott Duensing * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/singe/videoPlayer.h b/singe/videoPlayer.h index d76b3ea75..9300e9ba8 100644 --- a/singe/videoPlayer.h +++ b/singe/videoPlayer.h @@ -1,7 +1,7 @@ /* * * Singe 2 - * Copyright (C) 2019 Scott Duensing + * Copyright (C) 2006-2020 Scott Duensing * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License