From 9664cd48fe6ee2343443940df8fd49af3f3fb5ba Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Sun, 25 May 2025 16:28:35 -0400 Subject: [PATCH 01/86] Code compiles, now working on getting configure.ac fixed --- Headers/AppKit/NSMovie.h | 5 +- Headers/AppKit/NSMovieView.h | 17 +++++ Source/NSMovie.m | 61 +++++++++++----- Source/NSMovieView.m | 138 ++++++++++++++++++++++++++++++++++- 4 files changed, 195 insertions(+), 26 deletions(-) diff --git a/Headers/AppKit/NSMovie.h b/Headers/AppKit/NSMovie.h index 657be1159c..c0b9977ba9 100644 --- a/Headers/AppKit/NSMovie.h +++ b/Headers/AppKit/NSMovie.h @@ -41,8 +41,9 @@ APPKIT_EXPORT_CLASS @interface NSMovie : NSObject { @private - NSData* _movie; - NSURL* _url; + NSData* _movie; + NSURL* _url; + BOOL _tmp; } + (NSArray*) movieUnfilteredFileTypes; diff --git a/Headers/AppKit/NSMovieView.h b/Headers/AppKit/NSMovieView.h index dc96935b3c..fa1ede9dd8 100644 --- a/Headers/AppKit/NSMovieView.h +++ b/Headers/AppKit/NSMovieView.h @@ -32,6 +32,11 @@ #import +#include +#include +#include +#include + @class NSMovie; typedef enum { @@ -56,6 +61,18 @@ APPKIT_EXPORT_CLASS unsigned int editable: 1; unsigned int reserved: 24; } _flags; + BOOL _playing; + NSTimer *_decodeTimer; + + // libav specific... + NSImage *_currentFrame; + AVFormatContext *_formatContext; + AVCodecContext *_codecContext; + AVFrame *_avframe; + AVFrame *_avframeRGB; + struct SwsContext *_swsCtx; + int _videoStreamIndex; + uint8_t *_buffer; } - (void) setMovie: (NSMovie*)movie; diff --git a/Source/NSMovie.m b/Source/NSMovie.m index 2c5a8ded27..4f61b8d604 100644 --- a/Source/NSMovie.m +++ b/Source/NSMovie.m @@ -30,20 +30,38 @@ #import #import #import +#import +#import + #import "AppKit/NSMovie.h" #import "AppKit/NSPasteboard.h" +NSString *_writeDataToTempFile(NSData *data) +{ + NSString *tempDirectory = NSTemporaryDirectory(); + NSString *filename = [NSString stringWithFormat: @"tmpfile-%@.dat", [[NSUUID UUID] UUIDString]]; + NSString *filepath = [tempDirectory stringByAppendingPathComponent: filename]; + NSError *error = nil; + + BOOL success = [data writeToFile: filepath options: NSDataWritingAtomic error: &error]; + if (success) + { + return nil; + } + + return filepath; +} + @implementation NSMovie + (NSArray*) movieUnfilteredFileTypes { - return [NSArray arrayWithObject: @"mov"]; + return [NSArray arrayWithObjects: @"mp4", @"mov", @"avi", @"flv", @"mkv", @"webm", nil ]; } + (NSArray*) movieUnfilteredPasteboardTypes { - // FIXME - return [NSArray arrayWithObject: @"QuickTimeMovie"]; + return [self movieUnfilteredFileTypes]; } + (BOOL) canInitWithPasteboard: (NSPasteboard*)pasteboard @@ -61,31 +79,33 @@ - (id) initWithData: (NSData *)movie RELEASE(self); return nil; } - - [super init]; - ASSIGN(_movie, movie); + self = [super init]; + if (self != nil) + { + NSString *filepath = _writeDataToTempFile(_movie); + + _url = [NSURL fileURLWithPath: filepath]; + _tmp = YES; + ASSIGN(_movie, movie); + } + return self; } - (id) initWithMovie: (void*)movie { - //FIXME - - return self; + return [self initWithData: movie]; } - (id) initWithURL: (NSURL*)url byReference: (BOOL)byRef { - NSData* data = [url resourceDataUsingCache: YES]; - - self = [self initWithData: data]; - - if (byRef) + self = [super init]; + if (self != nil) { ASSIGN(_url, url); } - + return self; } @@ -94,12 +114,11 @@ - (id) initWithPasteboard: (NSPasteboard*)pasteboard NSString *type; NSData* data; - type = [pasteboard availableTypeFromArray: - [object_getClass(self) movieUnfilteredPasteboardTypes]]; + type = + [pasteboard availableTypeFromArray: + [object_getClass(self) movieUnfilteredPasteboardTypes]]; if (type == nil) { - //NSArray *array = [pasteboard propertyListForType: NSFilenamesPboardType]; - // FIXME data = nil; } else @@ -120,9 +139,11 @@ - (id) initWithPasteboard: (NSPasteboard*)pasteboard - (void) dealloc { + _tmp = NO; + [[NSFileManager defaultManager] removeFileAtPath: [_url path] error: nil]; TEST_RELEASE(_url); TEST_RELEASE(_movie); - + [super dealloc]; } diff --git a/Source/NSMovieView.m b/Source/NSMovieView.m index a337a05529..ec5ab8279f 100644 --- a/Source/NSMovieView.m +++ b/Source/NSMovieView.m @@ -28,16 +28,125 @@ #import #import +#import #import + +#import "AppKit/NSColor.h" +#import "AppKit/NSGraphics.h" +#import "AppKit/NSImage.h" +#import "AppKit/NSImageRep.h" #import "AppKit/NSMovie.h" #import "AppKit/NSMovieView.h" #import "AppKit/NSPasteboard.h" @implementation NSMovieView +// private method to display frames... +- (void) _updateImage: (NSImage *)image +{ + _currentFrame = image; + [self setNeedsDisplay:YES]; +} + +- (void) _prepareDecoder +{ + NSString *moviePath = [[_movie URL] path]; + + _formatContext = avformat_alloc_context(); + if (avformat_open_input(&_formatContext, [moviePath UTF8String], NULL, NULL) != 0) return; + if (avformat_find_stream_info(_formatContext, NULL) < 0) return; + + _videoStreamIndex = -1; + for (int i = 0; i < _formatContext->nb_streams; i++) + { + if (_formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) + { + _videoStreamIndex = i; + break; + } + } + + if (_videoStreamIndex == -1) return; + + AVCodecParameters *codecPar = _formatContext->streams[_videoStreamIndex]->codecpar; + const AVCodec *codec = avcodec_find_decoder(codecPar->codec_id); + + _codecContext = avcodec_alloc_context3(codec); + avcodec_parameters_to_context(_codecContext, codecPar); + if (avcodec_open2(_codecContext, codec, NULL) < 0) return; + + _avframe = av_frame_alloc(); + _avframeRGB = av_frame_alloc(); + + int numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, _codecContext->width, _codecContext->height, 1); + _buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t)); + av_image_fill_arrays(_avframeRGB->data, _avframeRGB->linesize, _buffer, AV_PIX_FMT_RGB24, + _codecContext->width, _codecContext->height, 1); + + _swsCtx = sws_getContext(_codecContext->width, _codecContext->height, _codecContext->pix_fmt, + _codecContext->width, _codecContext->height, AV_PIX_FMT_RGB24, + SWS_BILINEAR, NULL, NULL, NULL); + +} + +- (void) _decodeAndDisplayNextFrame +{ + AVPacket packet; + + av_init_packet(&packet); + packet.data = NULL; + packet.size = 0; + + while (av_read_frame(_formatContext, &packet) >= 0) + { + if (!_playing) break; + + if (packet.stream_index == _videoStreamIndex) + { + avcodec_send_packet(_codecContext, &packet); + if (avcodec_receive_frame(_codecContext, _avframe) == 0) + { + sws_scale(_swsCtx, (const uint8_t * const *)_avframe->data, _avframe->linesize, 0, + _codecContext->height, _avframeRGB->data, _avframeRGB->linesize); + + NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] + initWithBitmapDataPlanes: _avframeRGB->data + pixelsWide: _codecContext->width + pixelsHigh: _codecContext->height + bitsPerSample: 8 + samplesPerPixel: 3 + hasAlpha: NO + isPlanar: NO + colorSpaceName: NSCalibratedRGBColorSpace + bytesPerRow: _avframeRGB->linesize[0] + bitsPerPixel: 24]; + + NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize(_codecContext->width, _codecContext->height)]; + [image addRepresentation:rep]; + + [self performSelectorOnMainThread: @selector(_updateImage:) + withObject: image + waitUntilDone: NO]; + break; + } + } + av_packet_unref(&packet); + } +} + +- (void) drawRect: (NSRect)dirtyRect +{ + [super drawRect: dirtyRect]; + if (_currentFrame) + { + [_currentFrame drawInRect: [self bounds]]; + } +} + - (void) setMovie: (NSMovie*)movie { ASSIGN(_movie, movie); + [self _prepareDecoder]; } - (NSMovie*) movie @@ -47,18 +156,39 @@ - (NSMovie*) movie - (void) start: (id)sender { - //FIXME + _playing = YES; + _rate = 1.0 / 30.0; + _volume = 1.0; + + _decodeTimer = + [NSTimer scheduledTimerWithTimeInterval: _rate + target: self + selector: @selector(decodeAndDisplayNextFrame) + userInfo: nil + repeats: YES]; } - (void) stop: (id)sender { - //FIXME + _playing = NO; + + if (_decodeTimer) + { + [_decodeTimer invalidate]; + _decodeTimer = nil; + } + + if (_avframe) av_frame_free(&_avframe); + if (_avframeRGB) av_frame_free(&_avframeRGB); + if (_buffer) av_free(_buffer); + if (_codecContext) avcodec_free_context(&_codecContext); + if (_formatContext) avformat_close_input(&_formatContext); + if (_swsCtx) sws_freeContext(_swsCtx); } - (BOOL) isPlaying { - //FIXME - return NO; + return _playing; } - (void) gotoPosterFrame: (id)sender From 31f0b8ecfbaa8c591cb8dd634146621ad5b1aefb Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Sun, 25 May 2025 17:30:16 -0400 Subject: [PATCH 02/86] Update to be able to play content using NSMovie, add configure.ac changes, and config.make/config.h changes --- Headers/Additions/GNUstepGUI/config.h.in | 3 + Headers/AppKit/NSMovieView.h | 6 + Source/GNUmakefile.preamble | 4 +- Source/NSMovie.m | 2 +- Source/NSMovieView.m | 11 +- config.make.in | 5 + configure | 4273 ++++++++++++---------- configure.ac | 20 + 8 files changed, 2377 insertions(+), 1947 deletions(-) diff --git a/Headers/Additions/GNUstepGUI/config.h.in b/Headers/Additions/GNUstepGUI/config.h.in index 64f2cbcab1..a99ede2be4 100644 --- a/Headers/Additions/GNUstepGUI/config.h.in +++ b/Headers/Additions/GNUstepGUI/config.h.in @@ -148,6 +148,9 @@ /* MagickCore >= 7 */ #undef MAGICKCORE_7_OR_NEWER +/* avcodec */ +#undef HAVE_AVCODEC + /* mntent structure member name */ #undef MNT_FSNAME diff --git a/Headers/AppKit/NSMovieView.h b/Headers/AppKit/NSMovieView.h index fa1ede9dd8..1c9a90e94c 100644 --- a/Headers/AppKit/NSMovieView.h +++ b/Headers/AppKit/NSMovieView.h @@ -32,10 +32,14 @@ #import +#import "config.h" + +#ifdef HAVE_AVCODEC #include #include #include #include +#endif @class NSMovie; @@ -66,11 +70,13 @@ APPKIT_EXPORT_CLASS // libav specific... NSImage *_currentFrame; +#ifdef HAVE_AVCODEC AVFormatContext *_formatContext; AVCodecContext *_codecContext; AVFrame *_avframe; AVFrame *_avframeRGB; struct SwsContext *_swsCtx; +#endif int _videoStreamIndex; uint8_t *_buffer; } diff --git a/Source/GNUmakefile.preamble b/Source/GNUmakefile.preamble index 183a8b073a..3e0e318b2d 100644 --- a/Source/GNUmakefile.preamble +++ b/Source/GNUmakefile.preamble @@ -52,7 +52,7 @@ endif ADDITIONAL_OBJCFLAGS = -Wall # Additional flags to pass to the C compiler -# ADDITIONAL_CFLAGS = +ADDITIONAL_CFLAGS = $(MOVIE_BASE_CFLAGS) # Additional include directories the compiler should search ADDITIONAL_INCLUDE_DIRS += -I../Headers/Additions -I../Headers \ @@ -62,7 +62,7 @@ ADDITIONAL_INCLUDE_DIRS += -I../Headers/Additions -I../Headers \ # ADDITIONAL_LDFLAGS = # Additional library directories the linker should search -# ADDITIONAL_LIB_DIRS = +ADDITIONAL_LIB_DIRS = $(MOVIE_BASE_LIBS) # # Sparc systems cannot load tiff files due to some problem compiling diff --git a/Source/NSMovie.m b/Source/NSMovie.m index 4f61b8d604..10127d9466 100644 --- a/Source/NSMovie.m +++ b/Source/NSMovie.m @@ -140,7 +140,7 @@ - (id) initWithPasteboard: (NSPasteboard*)pasteboard - (void) dealloc { _tmp = NO; - [[NSFileManager defaultManager] removeFileAtPath: [_url path] error: nil]; + [[NSFileManager defaultManager] removeFileAtPath: [_url path] handler: nil]; TEST_RELEASE(_url); TEST_RELEASE(_movie); diff --git a/Source/NSMovieView.m b/Source/NSMovieView.m index ec5ab8279f..6d97c754ed 100644 --- a/Source/NSMovieView.m +++ b/Source/NSMovieView.m @@ -39,6 +39,8 @@ #import "AppKit/NSMovieView.h" #import "AppKit/NSPasteboard.h" +#import "config.h" + @implementation NSMovieView // private method to display frames... @@ -50,8 +52,9 @@ - (void) _updateImage: (NSImage *)image - (void) _prepareDecoder { +#ifdef HAVE_AVCODEC NSString *moviePath = [[_movie URL] path]; - + _formatContext = avformat_alloc_context(); if (avformat_open_input(&_formatContext, [moviePath UTF8String], NULL, NULL) != 0) return; if (avformat_find_stream_info(_formatContext, NULL) < 0) return; @@ -86,11 +89,12 @@ - (void) _prepareDecoder _swsCtx = sws_getContext(_codecContext->width, _codecContext->height, _codecContext->pix_fmt, _codecContext->width, _codecContext->height, AV_PIX_FMT_RGB24, SWS_BILINEAR, NULL, NULL, NULL); - +#endif } - (void) _decodeAndDisplayNextFrame { +#ifdef HAVE_AVCODEC AVPacket packet; av_init_packet(&packet); @@ -132,6 +136,7 @@ - (void) _decodeAndDisplayNextFrame } av_packet_unref(&packet); } +#endif } - (void) drawRect: (NSRect)dirtyRect @@ -178,12 +183,14 @@ - (void) stop: (id)sender _decodeTimer = nil; } +#ifdef HAVE_AVCODEC if (_avframe) av_frame_free(&_avframe); if (_avframeRGB) av_frame_free(&_avframeRGB); if (_buffer) av_free(_buffer); if (_codecContext) avcodec_free_context(&_codecContext); if (_formatContext) avformat_close_input(&_formatContext); if (_swsCtx) sws_freeContext(_swsCtx); +#endif } - (BOOL) isPlaying diff --git a/config.make.in b/config.make.in index f948caa0b6..b99379ab67 100644 --- a/config.make.in +++ b/config.make.in @@ -14,6 +14,11 @@ RECOGNIZER_BASE_LIBS=@RECOGNIZER_BASE_LIBS@ RECOGNIZER_BASE_CFLAGS=@RECOGNIZER_BASE_CFLAGS@ RECOGNIZER_ENGINE_CLASS=@RECOGNIZER_ENGINE_CLASS@ +# NSMovie +BUILD_MOVIE=@BUILD_MOVIE@ +MOVIE_BASE_LIBS=@MOVIE_BASE_LIBS@ +MOVIE_BASE_CFLAGS=@MOVIE_BASE_CFLAGS@ + # CUPS GSCUPS_CFLAGS = @GSCUPS_CFLAGS@ GSCUPS_LDFLAGS = @GSCUPS_LDFLAGS@ diff --git a/configure b/configure index 70dc2161b3..7572cb0508 100755 --- a/configure +++ b/configure @@ -1,9 +1,10 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69. +# Generated by GNU Autoconf 2.71. # # -# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, +# Inc. # # # This configure script is free software; the Free Software Foundation @@ -14,14 +15,16 @@ # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : +as_nop=: +if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else +else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( @@ -31,46 +34,46 @@ esac fi + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then +if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || @@ -79,13 +82,6 @@ if test "${PATH_SEPARATOR+set}" != set; then fi -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( @@ -94,8 +90,12 @@ case $0 in #(( for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS @@ -107,30 +107,10 @@ if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. @@ -152,20 +132,22 @@ esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -as_fn_exit 255 +printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + as_bourne_compatible="as_nop=: +if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST -else +else \$as_nop case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( @@ -185,42 +167,52 @@ as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } -if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : +if ( set x; as_fn_ret_success y && test x = \"\$1\" ) +then : -else +else \$as_nop exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 +blah=\$(echo \$(echo blah)) +test x\"\$blah\" = xblah || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && - test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 -test \$(( 1 + 1 )) = 2 || exit 1" - if (eval "$as_required") 2>/dev/null; then : + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" + if (eval "$as_required") 2>/dev/null +then : as_have_required=yes -else +else $as_nop as_have_required=no fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null +then : -else +else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. - as_shell=$as_dir/$as_base + as_shell=$as_dir$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null +then : CONFIG_SHELL=$as_shell as_have_required=yes - if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null +then : break 2 fi fi @@ -228,14 +220,21 @@ fi esac as_found=false done -$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : - CONFIG_SHELL=$SHELL as_have_required=yes -fi; } IFS=$as_save_IFS +if $as_found +then : + +else $as_nop + if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null +then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi +fi - if test "x$CONFIG_SHELL" != x; then : + if test "x$CONFIG_SHELL" != x +then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also @@ -253,18 +252,19 @@ esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi - if test x$as_have_required = xno; then : - $as_echo "$0: This script requires a shell more modern than all" - $as_echo "$0: the shells that I found on your system." - if test x${ZSH_VERSION+set} = xset ; then - $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" - $as_echo "$0: be upgraded to zsh 4.3.4 or later." + if test x$as_have_required = xno +then : + printf "%s\n" "$0: This script requires a shell more modern than all" + printf "%s\n" "$0: the shells that I found on your system." + if test ${ZSH_VERSION+y} ; then + printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" + printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else - $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, + printf "%s\n" "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." @@ -291,6 +291,7 @@ as_fn_unset () } as_unset=as_fn_unset + # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. @@ -308,6 +309,14 @@ as_fn_exit () as_fn_set_status $1 exit $1 } # as_fn_exit +# as_fn_nop +# --------- +# Do nothing but, unlike ":", preserve the value of $?. +as_fn_nop () +{ + return $? +} +as_nop=as_fn_nop # as_fn_mkdir_p # ------------- @@ -322,7 +331,7 @@ as_fn_mkdir_p () as_dirs= while :; do case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" @@ -331,7 +340,7 @@ $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | +printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -370,12 +379,13 @@ as_fn_executable_p () # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null +then : eval 'as_fn_append () { eval $1+=\$2 }' -else +else $as_nop as_fn_append () { eval $1=\$$1\$2 @@ -387,18 +397,27 @@ fi # as_fn_append # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : eval 'as_fn_arith () { as_val=$(( $* )) }' -else +else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith +# as_fn_nop +# --------- +# Do nothing but, unlike ":", preserve the value of $?. +as_fn_nop () +{ + return $? +} +as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- @@ -410,9 +429,9 @@ as_fn_error () as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - $as_echo "$as_me: error: $2" >&2 + printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error @@ -439,7 +458,7 @@ as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | +printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q @@ -483,7 +502,7 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || - { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall @@ -497,6 +516,10 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits exit } + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) @@ -510,6 +533,13 @@ case `echo -n x` in #((((( ECHO_N='-n';; esac +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + + rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -575,50 +605,46 @@ MFLAGS= MAKEFLAGS= # Identity of this package. -PACKAGE_NAME= -PACKAGE_TARNAME= -PACKAGE_VERSION= -PACKAGE_STRING= -PACKAGE_BUGREPORT= -PACKAGE_URL= +PACKAGE_NAME='' +PACKAGE_TARNAME='' +PACKAGE_VERSION='' +PACKAGE_STRING='' +PACKAGE_BUGREPORT='' +PACKAGE_URL='' ac_unique_file="Source/NSApplication.m" # Factoring default headers for most tests. ac_includes_default="\ -#include -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_SYS_STAT_H -# include +#include +#ifdef HAVE_STDIO_H +# include #endif -#ifdef STDC_HEADERS +#ifdef HAVE_STDLIB_H # include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif #endif #ifdef HAVE_STRING_H -# if !defined STDC_HEADERS && defined HAVE_MEMORY_H -# include -# endif # include #endif -#ifdef HAVE_STRINGS_H -# include -#endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif #ifdef HAVE_UNISTD_H # include #endif" +ac_header_c_list= ac_subst_vars='LTLIBOBJS LIBOBJS cross_compiling @@ -637,6 +663,8 @@ GSCUPS_LIBS GSCUPS_LDFLAGS GSCUPS_CFLAGS have_cups +MOVIE_BASE_CFLAGS +MOVIE_BASE_LIBS RECOGNIZER_ENGINE_CLASS RECOGNIZER_BASE_CFLAGS RECOGNIZER_BASE_LIBS @@ -654,8 +682,6 @@ IMAGEMAGICK_CFLAGS HAVE_LIBPNG_CONFIG TIFF_LIBS TIFF_CFLAGS -EGREP -GREP XMKMF PKG_CONFIG_LIBDIR PKG_CONFIG_PATH @@ -700,6 +726,7 @@ infodir docdir oldincludedir includedir +runstatedir localstatedir sharedstatedir sysconfdir @@ -740,6 +767,7 @@ enable_aspell enable_sound enable_speech enable_speech_recognizer +enable_movie enable_cups ' ac_precious_vars='build_alias @@ -801,6 +829,7 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' @@ -830,8 +859,6 @@ do *) ac_optarg=yes ;; esac - # Accept the important Cygnus configure options, so we can diagnose typos. - case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; @@ -872,9 +899,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" + as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" @@ -898,9 +925,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" + as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" @@ -1053,6 +1080,15 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1102,9 +1138,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" + as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" @@ -1118,9 +1154,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" + as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" @@ -1164,9 +1200,9 @@ Try \`$0 --help' for more information" *) # FIXME: should be removed in autoconf 3.0. - $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; @@ -1182,7 +1218,7 @@ if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; - *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi @@ -1190,7 +1226,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir + libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1246,7 +1282,7 @@ $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_myself" | +printf "%s\n" X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -1343,6 +1379,7 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -1389,6 +1426,7 @@ Optional Features: --disable-sound Disable sound --disable-speech Disable speech server --disable-speech-recognizer Disable speech recognition server + --disable-movie Disable NSMovie/NSMovieView functionality --disable-cups Disable cups printing support Optional Packages: @@ -1451,9 +1489,9 @@ if test "$ac_init_help" = "recursive"; then case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; @@ -1481,7 +1519,8 @@ esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } - # Check for guested configure. + # Check for configure.gnu first; this name is used for a wrapper for + # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive @@ -1489,7 +1528,7 @@ ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix echo && $SHELL "$ac_srcdir/configure" --help=recursive else - $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done @@ -1499,9 +1538,9 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure -generated by GNU Autoconf 2.69 +generated by GNU Autoconf 2.71 -Copyright (C) 2012 Free Software Foundation, Inc. +Copyright (C) 2021 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -1518,14 +1557,14 @@ fi ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext + rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -1533,14 +1572,15 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err - } && test -s conftest.$ac_objext; then : + } && test -s conftest.$ac_objext +then : ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 @@ -1562,7 +1602,7 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -1570,14 +1610,15 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err - }; then : + } +then : ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 @@ -1593,14 +1634,14 @@ fi ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest$ac_exeext + rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -1608,17 +1649,18 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext - }; then : + } +then : ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 @@ -1639,11 +1681,12 @@ fi ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. @@ -1651,16 +1694,9 @@ else #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif + which can conflict with char $2 (); below. */ +#include #undef $2 /* Override any GCC internal prototype to avoid an error. @@ -1678,157 +1714,29 @@ choke me #endif int -main () +main (void) { return $2 (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : eval "$3=yes" -else +else $as_nop eval "$3=no" fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func -# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists, giving a warning if it cannot be compiled using -# the include files in INCLUDES and setting the cache variable VAR -# accordingly. -ac_fn_c_check_header_mongrel () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if eval \${$3+:} false; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -else - # Is the header compilable? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 -$as_echo_n "checking $2 usability... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_header_compiler=yes -else - ac_header_compiler=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 -$as_echo "$ac_header_compiler" >&6; } - -# Is the header present? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 -$as_echo_n "checking $2 presence... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include <$2> -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - ac_header_preproc=yes -else - ac_header_preproc=no -fi -rm -f conftest.err conftest.i conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 -$as_echo "$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( - yes:no: ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 -$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; - no:yes:* ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 -$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 -$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 -$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 -$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; -esac - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=\$ac_header_compiler" -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_header_mongrel - -# ac_fn_c_try_run LINENO -# ---------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes -# that executables *can* be run. -ac_fn_c_try_run () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then : - ac_retval=0 -else - $as_echo "$as_me: program exited with status $ac_status" >&5 - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=$ac_status -fi - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_run - # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in @@ -1836,26 +1744,28 @@ fi ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : eval "$3=yes" -else +else $as_nop eval "$3=no" fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile @@ -1867,16 +1777,17 @@ $as_echo "$ac_res" >&6; } ac_fn_c_check_member () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 -$as_echo_n "checking for $2.$3... " >&6; } -if eval \${$4+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 +printf %s "checking for $2.$3... " >&6; } +if eval test \${$4+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int -main () +main (void) { static $2 ac_aggr; if (ac_aggr.$3) @@ -1885,14 +1796,15 @@ return 0; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : eval "$4=yes" -else +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int -main () +main (void) { static $2 ac_aggr; if (sizeof ac_aggr.$3) @@ -1901,29 +1813,50 @@ return 0; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : eval "$4=yes" -else +else $as_nop eval "$4=no" fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$4 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_member +ac_configure_args_raw= +for ac_arg +do + case $ac_arg in + *\'*) + ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append ac_configure_args_raw " '$ac_arg'" +done + +case $ac_configure_args_raw in + *$as_nl*) + ac_safe_unquote= ;; + *) + ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. + ac_unsafe_a="$ac_unsafe_z#~" + ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" + ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; +esac + cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was -generated by GNU Autoconf 2.69. Invocation command line was +generated by GNU Autoconf 2.71. Invocation command line was - $ $0 $@ + $ $0$ac_configure_args_raw _ACEOF exec 5>>config.log @@ -1956,8 +1889,12 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - $as_echo "PATH: $as_dir" + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + printf "%s\n" "PATH: $as_dir" done IFS=$as_save_IFS @@ -1992,7 +1929,7 @@ do | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) - ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; @@ -2027,11 +1964,13 @@ done # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? + # Sanitize IFS. + IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo - $as_echo "## ---------------- ## + printf "%s\n" "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo @@ -2042,8 +1981,8 @@ trap 'exit_status=$? case $ac_val in #( *${as_nl}*) case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( @@ -2067,7 +2006,7 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; ) echo - $as_echo "## ----------------- ## + printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo @@ -2075,14 +2014,14 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; do eval ac_val=\$$ac_var case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac - $as_echo "$ac_var='\''$ac_val'\''" + printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then - $as_echo "## ------------------- ## + printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo @@ -2090,15 +2029,15 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; do eval ac_val=\$$ac_var case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac - $as_echo "$ac_var='\''$ac_val'\''" + printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then - $as_echo "## ----------- ## + printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo @@ -2106,8 +2045,8 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; echo fi test "$ac_signal" != 0 && - $as_echo "$as_me: caught signal $ac_signal" - $as_echo "$as_me: exit $exit_status" + printf "%s\n" "$as_me: caught signal $ac_signal" + printf "%s\n" "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && @@ -2121,63 +2060,48 @@ ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h -$as_echo "/* confdefs.h */" > confdefs.h +printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. -cat >>confdefs.h <<_ACEOF -#define PACKAGE_NAME "$PACKAGE_NAME" -_ACEOF +printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_TARNAME "$PACKAGE_TARNAME" -_ACEOF +printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_VERSION "$PACKAGE_VERSION" -_ACEOF +printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_STRING "$PACKAGE_STRING" -_ACEOF +printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" -_ACEOF +printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_URL "$PACKAGE_URL" -_ACEOF +printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. -ac_site_file1=NONE -ac_site_file2=NONE if test -n "$CONFIG_SITE"; then - # We do not want a PATH search for config.site. - case $CONFIG_SITE in #(( - -*) ac_site_file1=./$CONFIG_SITE;; - */*) ac_site_file1=$CONFIG_SITE;; - *) ac_site_file1=./$CONFIG_SITE;; - esac + ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then - ac_site_file1=$prefix/share/config.site - ac_site_file2=$prefix/etc/config.site + ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else - ac_site_file1=$ac_default_prefix/share/config.site - ac_site_file2=$ac_default_prefix/etc/config.site + ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi -for ac_site_file in "$ac_site_file1" "$ac_site_file2" + +for ac_site_file in $ac_site_files do - test "x$ac_site_file" = xNONE && continue - if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -$as_echo "$as_me: loading site script $ac_site_file" >&6;} + case $ac_site_file in #( + */*) : + ;; #( + *) : + ac_site_file=./$ac_site_file ;; +esac + if test -f "$ac_site_file" && test -r "$ac_site_file"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ - || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi @@ -2187,129 +2111,517 @@ if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 -$as_echo "$as_me: loading cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 -$as_echo "$as_me: creating cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi -# Check that the precious variables saved in the cache have kept the same -# value. -ac_cache_corrupted=false -for ac_var in $ac_precious_vars; do - eval ac_old_set=\$ac_cv_env_${ac_var}_set - eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val=\$ac_cv_env_${ac_var}_value - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) - if test "x$ac_old_val" != "x$ac_new_val"; then - # differences in whitespace do not lead to failure. - ac_old_val_w=`echo x $ac_old_val` - ac_new_val_w=`echo x $ac_new_val` - if test "$ac_old_val_w" != "$ac_new_val_w"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 -$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} - ac_cache_corrupted=: - else - { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 -$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} - eval $ac_var=\$ac_old_val - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 -$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 -$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} - fi;; - esac - # Pass precious variables to config.status. - if test "$ac_new_set" = set; then - case $ac_new_val in - *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; - *) ac_arg=$ac_var=$ac_new_val ;; - esac - case " $ac_configure_args " in - *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) as_fn_append ac_configure_args " '$ac_arg'" ;; - esac - fi -done -if $ac_cache_corrupted; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 -fi -## -------------------- ## -## Main body of script. ## -## -------------------- ## +# Test code for whether the C compiler supports C89 (global declarations) +ac_c_conftest_c89_globals=' +/* Does the compiler advertise C89 conformance? + Do not test the value of __STDC__, because some compilers set it to 0 + while being otherwise adequately conformant. */ +#if !defined __STDC__ +# error "Compiler does not advertise C89 conformance" +#endif -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ +struct buf { int x; }; +struct buf * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not \xHH hex character constants. + These do not provoke an error unfortunately, instead are silently treated + as an "x". The following induces an error, until -std is added to get + proper ANSI mode. Curiously \x00 != x always comes out true, for an + array size at least. It is necessary to write \x00 == 0 to get something + that is true only with -std. */ +int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) '\''x'\'' +int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), + int, int);' -# If GNUSTEP_MAKEFILES is undefined, try to use gnustep-config to determine it. -if test -z "$GNUSTEP_MAKEFILES"; then - GNUSTEP_MAKEFILES=`gnustep-config --variable=GNUSTEP_MAKEFILES 2>&5` -fi +# Test code for whether the C compiler supports C89 (body of main). +ac_c_conftest_c89_main=' +ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); +' -if test -z "$GNUSTEP_MAKEFILES"; then - as_fn_error $? "You must have the gnustep-make package installed and set up the GNUSTEP_MAKEFILES environment variable to contain the path to the makefiles directory before configuring!" "$LINENO" 5 -fi +# Test code for whether the C compiler supports C99 (global declarations) +ac_c_conftest_c99_globals=' +// Does the compiler advertise C99 conformance? +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L +# error "Compiler does not advertise C99 conformance" +#endif -#-------------------------------------------------------------------- -# Use config.guess, config.sub and install-sh provided by gnustep-make -#-------------------------------------------------------------------- -ac_aux_dir= -for ac_dir in $GNUSTEP_MAKEFILES "$srcdir"/$GNUSTEP_MAKEFILES; do - if test -f "$ac_dir/install-sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install-sh -c" - break - elif test -f "$ac_dir/install.sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install.sh -c" - break - elif test -f "$ac_dir/shtool"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/shtool install -c" - break - fi +#include +extern int puts (const char *); +extern int printf (const char *, ...); +extern int dprintf (int, const char *, ...); +extern void *malloc (size_t); + +// Check varargs macros. These examples are taken from C99 6.10.3.5. +// dprintf is used instead of fprintf to avoid needing to declare +// FILE and stderr. +#define debug(...) dprintf (2, __VA_ARGS__) +#define showlist(...) puts (#__VA_ARGS__) +#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) +static void +test_varargs_macros (void) +{ + int x = 1234; + int y = 5678; + debug ("Flag"); + debug ("X = %d\n", x); + showlist (The first, second, and third items.); + report (x>y, "x is %d but y is %d", x, y); +} + +// Check long long types. +#define BIG64 18446744073709551615ull +#define BIG32 4294967295ul +#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) +#if !BIG_OK + #error "your preprocessor is broken" +#endif +#if BIG_OK +#else + #error "your preprocessor is broken" +#endif +static long long int bignum = -9223372036854775807LL; +static unsigned long long int ubignum = BIG64; + +struct incomplete_array +{ + int datasize; + double data[]; +}; + +struct named_init { + int number; + const wchar_t *name; + double average; +}; + +typedef const char *ccp; + +static inline int +test_restrict (ccp restrict text) +{ + // See if C++-style comments work. + // Iterate through items via the restricted pointer. + // Also check for declarations in for loops. + for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) + continue; + return 0; +} + +// Check varargs and va_copy. +static bool +test_varargs (const char *format, ...) +{ + va_list args; + va_start (args, format); + va_list args_copy; + va_copy (args_copy, args); + + const char *str = ""; + int number = 0; + float fnumber = 0; + + while (*format) + { + switch (*format++) + { + case '\''s'\'': // string + str = va_arg (args_copy, const char *); + break; + case '\''d'\'': // int + number = va_arg (args_copy, int); + break; + case '\''f'\'': // float + fnumber = va_arg (args_copy, double); + break; + default: + break; + } + } + va_end (args_copy); + va_end (args); + + return *str && number && fnumber; +} +' + +# Test code for whether the C compiler supports C99 (body of main). +ac_c_conftest_c99_main=' + // Check bool. + _Bool success = false; + success |= (argc != 0); + + // Check restrict. + if (test_restrict ("String literal") == 0) + success = true; + char *restrict newvar = "Another string"; + + // Check varargs. + success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); + test_varargs_macros (); + + // Check flexible array members. + struct incomplete_array *ia = + malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); + ia->datasize = 10; + for (int i = 0; i < ia->datasize; ++i) + ia->data[i] = i * 1.234; + + // Check named initializers. + struct named_init ni = { + .number = 34, + .name = L"Test wide string", + .average = 543.34343, + }; + + ni.number = 58; + + int dynamic_array[ni.number]; + dynamic_array[0] = argv[0][0]; + dynamic_array[ni.number - 1] = 543; + + // work around unused variable warnings + ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' + || dynamic_array[ni.number - 1] != 543); +' + +# Test code for whether the C compiler supports C11 (global declarations) +ac_c_conftest_c11_globals=' +// Does the compiler advertise C11 conformance? +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L +# error "Compiler does not advertise C11 conformance" +#endif + +// Check _Alignas. +char _Alignas (double) aligned_as_double; +char _Alignas (0) no_special_alignment; +extern char aligned_as_int; +char _Alignas (0) _Alignas (int) aligned_as_int; + +// Check _Alignof. +enum +{ + int_alignment = _Alignof (int), + int_array_alignment = _Alignof (int[100]), + char_alignment = _Alignof (char) +}; +_Static_assert (0 < -_Alignof (int), "_Alignof is signed"); + +// Check _Noreturn. +int _Noreturn does_not_return (void) { for (;;) continue; } + +// Check _Static_assert. +struct test_static_assert +{ + int x; + _Static_assert (sizeof (int) <= sizeof (long int), + "_Static_assert does not work in struct"); + long int y; +}; + +// Check UTF-8 literals. +#define u8 syntax error! +char const utf8_literal[] = u8"happens to be ASCII" "another string"; + +// Check duplicate typedefs. +typedef long *long_ptr; +typedef long int *long_ptr; +typedef long_ptr long_ptr; + +// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. +struct anonymous +{ + union { + struct { int i; int j; }; + struct { int k; long int l; } w; + }; + int m; +} v1; +' + +# Test code for whether the C compiler supports C11 (body of main). +ac_c_conftest_c11_main=' + _Static_assert ((offsetof (struct anonymous, i) + == offsetof (struct anonymous, w.k)), + "Anonymous union alignment botch"); + v1.i = 2; + v1.w.k = 5; + ok |= v1.i != 5; +' + +# Test code for whether the C compiler supports C11 (complete). +ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} +${ac_c_conftest_c99_globals} +${ac_c_conftest_c11_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + ${ac_c_conftest_c99_main} + ${ac_c_conftest_c11_main} + return ok; +} +" + +# Test code for whether the C compiler supports C99 (complete). +ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} +${ac_c_conftest_c99_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + ${ac_c_conftest_c99_main} + return ok; +} +" + +# Test code for whether the C compiler supports C89 (complete). +ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + return ok; +} +" + +as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" +as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" +as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" +as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" +as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" +as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" +as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" +as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" +as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" + +# Auxiliary files required by this configure script. +ac_aux_files="config.guess config.sub" + +# Locations in which to look for auxiliary files. +ac_aux_dir_candidates="$GNUSTEP_MAKEFILES" + +# Search for a directory containing all of the required auxiliary files, +# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. +# If we don't find one directory that contains all the files we need, +# we report the set of missing files from the *first* directory in +# $ac_aux_dir_candidates and give up. +ac_missing_aux_files="" +ac_first_candidate=: +printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in $ac_aux_dir_candidates +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + as_found=: + + printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 + ac_aux_dir_found=yes + ac_install_sh= + for ac_aux in $ac_aux_files + do + # As a special case, if "install-sh" is required, that requirement + # can be satisfied by any of "install-sh", "install.sh", or "shtool", + # and $ac_install_sh is set appropriately for whichever one is found. + if test x"$ac_aux" = x"install-sh" + then + if test -f "${as_dir}install-sh"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 + ac_install_sh="${as_dir}install-sh -c" + elif test -f "${as_dir}install.sh"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 + ac_install_sh="${as_dir}install.sh -c" + elif test -f "${as_dir}shtool"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 + ac_install_sh="${as_dir}shtool install -c" + else + ac_aux_dir_found=no + if $ac_first_candidate; then + ac_missing_aux_files="${ac_missing_aux_files} install-sh" + else + break + fi + fi + else + if test -f "${as_dir}${ac_aux}"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 + else + ac_aux_dir_found=no + if $ac_first_candidate; then + ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" + else + break + fi + fi + fi + done + if test "$ac_aux_dir_found" = yes; then + ac_aux_dir="$as_dir" + break + fi + ac_first_candidate=false + + as_found=false done -if test -z "$ac_aux_dir"; then - as_fn_error $? "cannot find install-sh, install.sh, or shtool in $GNUSTEP_MAKEFILES \"$srcdir\"/$GNUSTEP_MAKEFILES" "$LINENO" 5 +IFS=$as_save_IFS +if $as_found +then : + +else $as_nop + as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 fi + # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. -ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. -ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. -ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. +if test -f "${ac_aux_dir}config.guess"; then + ac_config_guess="$SHELL ${ac_aux_dir}config.guess" +fi +if test -f "${ac_aux_dir}config.sub"; then + ac_config_sub="$SHELL ${ac_aux_dir}config.sub" +fi +if test -f "$ac_aux_dir/configure"; then + ac_configure="$SHELL ${ac_aux_dir}configure" +fi +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' + and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + +# If GNUSTEP_MAKEFILES is undefined, try to use gnustep-config to determine it. +if test -z "$GNUSTEP_MAKEFILES"; then + GNUSTEP_MAKEFILES=`gnustep-config --variable=GNUSTEP_MAKEFILES 2>&5` +fi + +if test -z "$GNUSTEP_MAKEFILES"; then + as_fn_error $? "You must have the gnustep-make package installed and set up the GNUSTEP_MAKEFILES environment variable to contain the path to the makefiles directory before configuring!" "$LINENO" 5 +fi + +#-------------------------------------------------------------------- +# Use config.guess, config.sub and install-sh provided by gnustep-make +#-------------------------------------------------------------------- ac_config_headers="$ac_config_headers Headers/Additions/GNUstepGUI/config.h" @@ -2318,26 +2630,30 @@ ac_config_headers="$ac_config_headers Headers/Additions/GNUstepGUI/config.h" #-------------------------------------------------------------------- # Determine the host, build, and target systems #-------------------------------------------------------------------- -# Make sure we can run config.sub. -$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || - as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 -$as_echo_n "checking build system type... " >&6; } -if ${ac_cv_build+:} false; then : - $as_echo_n "(cached) " >&6 -else + + + + # Make sure we can run config.sub. +$SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +printf %s "checking build system type... " >&6; } +if test ${ac_cv_build+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_build_alias=$build_alias test "x$ac_build_alias" = x && - ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` + ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 -ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 +ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 -$as_echo "$ac_cv_build" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +printf "%s\n" "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; @@ -2356,21 +2672,22 @@ IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 -$as_echo_n "checking host system type... " >&6; } -if ${ac_cv_host+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +printf %s "checking host system type... " >&6; } +if test ${ac_cv_host+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else - ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 + ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 -$as_echo "$ac_cv_host" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +printf "%s\n" "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; @@ -2389,21 +2706,22 @@ IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 -$as_echo_n "checking target system type... " >&6; } -if ${ac_cv_target+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 +printf %s "checking target system type... " >&6; } +if test ${ac_cv_target+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test "x$target_alias" = x; then ac_cv_target=$ac_cv_host else - ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 + ac_cv_target=`$SHELL "${ac_aux_dir}config.sub" $target_alias` || + as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $target_alias failed" "$LINENO" 5 fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 -$as_echo "$ac_cv_target" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 +printf "%s\n" "$ac_cv_target" >&6; } case $ac_cv_target in *-*-*) ;; *) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; @@ -2439,10 +2757,10 @@ if test "$CC" = ""; then CC=$MAKECC else if test "$CC" != "$MAKECC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You are running configure with the compiler ($CC) set to a different value from that used by gnustep-make ($MAKECC). To a + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: You are running configure with the compiler ($CC) set to a different value from that used by gnustep-make ($MAKECC). To a void conflicts/problems, reconfigure/reinstall gnustep-make to use $CC or run the gnustep-base configure again with your CC environment var iable set to $MAKECC" >&5 -$as_echo "$as_me: WARNING: You are running configure with the compiler ($CC) set to a different value from that used by gnustep-make ($MAKECC). To a +printf "%s\n" "$as_me: WARNING: You are running configure with the compiler ($CC) set to a different value from that used by gnustep-make ($MAKECC). To a void conflicts/problems, reconfigure/reinstall gnustep-make to use $CC or run the gnustep-base configure again with your CC environment var iable set to $MAKECC" >&2;} fi @@ -2451,10 +2769,10 @@ if test "$CPP" = ""; then CPP=$MAKECPP else if test "$CPP" != "$MAKECPP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You are running configure with the preprocessor ($CPP) set to a different value from that used by gnustep-make ($MAKECPP). + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: You are running configure with the preprocessor ($CPP) set to a different value from that used by gnustep-make ($MAKECPP). To avoid conflicts/problems, reconfigure/reinstall gnustep-make to use $CPP or run the gnustep-base configure again with your CPP environ ment variable set to $MAKECPP" >&5 -$as_echo "$as_me: WARNING: You are running configure with the preprocessor ($CPP) set to a different value from that used by gnustep-make ($MAKECPP). +printf "%s\n" "$as_me: WARNING: You are running configure with the preprocessor ($CPP) set to a different value from that used by gnustep-make ($MAKECPP). To avoid conflicts/problems, reconfigure/reinstall gnustep-make to use $CPP or run the gnustep-base configure again with your CPP environ ment variable set to $MAKECPP" >&2;} fi @@ -2463,14 +2781,23 @@ if test "$CXX" = ""; then CXX=$MAKECXX else if test "$CXX" != "$MAKECXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You are running configure with the compiler ($CXX) set to a different value from that used by gnustep-make ($MAKECXX). To + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: You are running configure with the compiler ($CXX) set to a different value from that used by gnustep-make ($MAKECXX). To avoid conflicts/problems, reconfigure/reinstall gnustep-make to use $CXX or run the gnustep-base configure again with your CXX environment variable set to $MAKECXX" >&5 -$as_echo "$as_me: WARNING: You are running configure with the compiler ($CXX) set to a different value from that used by gnustep-make ($MAKECXX). To +printf "%s\n" "$as_me: WARNING: You are running configure with the compiler ($CXX) set to a different value from that used by gnustep-make ($MAKECXX). To avoid conflicts/problems, reconfigure/reinstall gnustep-make to use $CXX or run the gnustep-base configure again with your CXX environment variable set to $MAKECXX" >&2;} fi fi + + + + + + + + + ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -2479,11 +2806,12 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -2491,11 +2819,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2506,11 +2838,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -2519,11 +2851,12 @@ if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else @@ -2531,11 +2864,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2546,11 +2883,11 @@ fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then @@ -2558,8 +2895,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC @@ -2572,11 +2909,12 @@ if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -2584,11 +2922,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2599,11 +2941,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -2612,11 +2954,12 @@ fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -2625,15 +2968,19 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2649,18 +2996,18 @@ if test $ac_prog_rejected = yes; then # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift - ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -2671,11 +3018,12 @@ if test -z "$CC"; then do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -2683,11 +3031,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2698,11 +3050,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -2715,11 +3067,12 @@ if test -z "$CC"; then do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else @@ -2727,11 +3080,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2742,11 +3099,11 @@ fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -2758,8 +3115,8 @@ done else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC @@ -2767,25 +3124,129 @@ esac fi fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. +set dummy ${ac_tool_prefix}clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi -test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "clang", so it can be a program name with args. +set dummy clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="clang" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +fi + + +test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 -for ac_option in --version -v -V -qversion; do +for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -2795,7 +3256,7 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done @@ -2803,7 +3264,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; @@ -2815,9 +3276,9 @@ ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 -$as_echo_n "checking whether the C compiler works... " >&6; } -ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +printf %s "checking whether the C compiler works... " >&6; } +ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" @@ -2838,11 +3299,12 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, @@ -2859,7 +3321,7 @@ do # certainly right. break;; *.* ) - if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi @@ -2875,44 +3337,46 @@ do done test "$ac_cv_exeext" = no && ac_cv_exeext= -else +else $as_nop ac_file='' fi -if test -z "$ac_file"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -$as_echo "$as_me: failed program was:" >&5 +if test -z "$ac_file" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 -$as_echo_n "checking for C compiler default output file name... " >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 -$as_echo "$ac_file" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +printf %s "checking for C compiler default output file name... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +printf "%s\n" "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 -$as_echo_n "checking for suffix of executables... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +printf %s "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with @@ -2926,15 +3390,15 @@ for ac_file in conftest.exe conftest conftest.*; do * ) break;; esac done -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +else $as_nop + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 -$as_echo "$ac_cv_exeext" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +printf "%s\n" "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext @@ -2943,7 +3407,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; @@ -2955,8 +3419,8 @@ _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 -$as_echo_n "checking whether we are cross compiling... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +printf %s "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in @@ -2964,10 +3428,10 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in @@ -2975,39 +3439,40 @@ $as_echo "$ac_try_echo"; } >&5 *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot run C compiled programs. + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 -$as_echo "$cross_compiling" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 -$as_echo_n "checking for suffix of object files... " >&6; } -if ${ac_cv_objext+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +printf %s "checking for suffix of object files... " >&6; } +if test ${ac_cv_objext+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; @@ -3021,11 +3486,12 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in @@ -3034,31 +3500,32 @@ $as_echo "$ac_try_echo"; } >&5 break;; esac done -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 -$as_echo "$ac_cv_objext" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 -$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if ${ac_cv_c_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 +printf %s "checking whether the compiler supports GNU C... " >&6; } +if test ${ac_cv_c_compiler_gnu+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { #ifndef __GNUC__ choke me @@ -3068,29 +3535,33 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_compiler_gnu=yes -else +else $as_nop ac_compiler_gnu=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -$as_echo "$ac_cv_c_compiler_gnu" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } +ac_compiler_gnu=$ac_cv_c_compiler_gnu + if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi -ac_test_CFLAGS=${CFLAGS+set} +ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -$as_echo_n "checking whether $CC accepts -g... " >&6; } -if ${ac_cv_prog_cc_g+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +printf %s "checking whether $CC accepts -g... " >&6; } +if test ${ac_cv_prog_cc_g+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no @@ -3099,57 +3570,60 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_g=yes -else +else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : -else +else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_g=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -$as_echo "$ac_cv_prog_cc_g" >&6; } -if test "$ac_test_CFLAGS" = set; then +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +printf "%s\n" "$ac_cv_prog_cc_g" >&6; } +if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then @@ -3164,94 +3638,144 @@ else CFLAGS= fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 -$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if ${ac_cv_prog_cc_c89+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_prog_cc_c89=no +ac_prog_cc_stdc=no +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 +printf %s "checking for $CC option to enable C11 features... " >&6; } +if test ${ac_cv_prog_cc_c11+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#include -#include -struct stat; -/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ -struct buf { int x; }; -FILE * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not '\xHH' hex character constants. - These don't provoke an error unfortunately, instead are silently treated - as 'x'. The following induces an error, until -std is added to get - proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an - array size at least. It's necessary to write '\x00'==0 to get something - that's true only with -std. */ -int osf4_cc_array ['\x00' == 0 ? 1 : -1]; +$ac_c_conftest_c11_program +_ACEOF +for ac_arg in '' -std=gnu11 +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c11=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c11" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) 'x' -int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; +if test "x$ac_cv_prog_cc_c11" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c11" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 +printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } + CC="$CC $ac_cv_prog_cc_c11" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 + ac_prog_cc_stdc=c11 +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 +printf %s "checking for $CC option to enable C99 features... " >&6; } +if test ${ac_cv_prog_cc_c99+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c99=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c99_program +_ACEOF +for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c99=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c99" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); -int argc; -char **argv; -int -main () -{ -return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; - ; - return 0; -} +if test "x$ac_cv_prog_cc_c99" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c99" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 +printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } + CC="$CC $ac_cv_prog_cc_c99" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 + ac_prog_cc_stdc=c99 +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 +printf %s "checking for $CC option to enable C89 features... " >&6; } +if test ${ac_cv_prog_cc_c89+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c89_program _ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ - -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO"; then : + if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_c89=$ac_arg fi -rm -f core conftest.err conftest.$ac_objext +rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC - fi -# AC_CACHE_VAL -case "x$ac_cv_prog_cc_c89" in - x) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -$as_echo "none needed" >&6; } ;; - xno) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -$as_echo "unsupported" >&6; } ;; - *) - CC="$CC $ac_cv_prog_cc_c89" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; -esac -if test "x$ac_cv_prog_cc_c89" != xno; then : +if test "x$ac_cv_prog_cc_c89" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c89" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } + CC="$CC $ac_cv_prog_cc_c89" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 + ac_prog_cc_stdc=c89 +fi fi ac_ext=c @@ -3265,40 +3789,36 @@ ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 -$as_echo_n "checking how to run the C preprocessor... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +printf %s "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then - if ${ac_cv_prog_CPP+:} false; then : - $as_echo_n "(cached) " >&6 -else - # Double quotes because CPP needs to be expanded - for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + if test ${ac_cv_prog_CPP+y} +then : + printf %s "(cached) " >&6 +else $as_nop + # Double quotes because $CC needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif +#include Syntax error _ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : +if ac_fn_c_try_cpp "$LINENO" +then : -else +else $as_nop # Broken: fails on valid input. continue fi @@ -3310,10 +3830,11 @@ rm -f conftest.err conftest.i conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : +if ac_fn_c_try_cpp "$LINENO" +then : # Broken: success on invalid input. continue -else +else $as_nop # Passes both tests. ac_preproc_ok=: break @@ -3323,7 +3844,8 @@ rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : +if $ac_preproc_ok +then : break fi @@ -3335,29 +3857,24 @@ fi else ac_cv_prog_CPP=$CPP fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 -$as_echo "$CPP" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +printf "%s\n" "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif +#include Syntax error _ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : +if ac_fn_c_try_cpp "$LINENO" +then : -else +else $as_nop # Broken: fails on valid input. continue fi @@ -3369,10 +3886,11 @@ rm -f conftest.err conftest.i conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : +if ac_fn_c_try_cpp "$LINENO" +then : # Broken: success on invalid input. continue -else +else $as_nop # Passes both tests. ac_preproc_ok=: break @@ -3382,11 +3900,12 @@ rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : +if $ac_preproc_ok +then : -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +else $as_nop + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi @@ -3403,11 +3922,12 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu #-------------------------------------------------------------------- # Extract the first word of "whoami", so it can be a program name with args. set dummy whoami; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_WHOAMI+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_WHOAMI+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $WHOAMI in [\\/]* | ?:[\\/]*) ac_cv_path_WHOAMI="$WHOAMI" # Let the user override the test with a path. @@ -3418,11 +3938,15 @@ as_dummy="$PATH:/usr/ucb" for as_dir in $as_dummy do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_WHOAMI="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_WHOAMI="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3435,11 +3959,11 @@ esac fi WHOAMI=$ac_cv_path_WHOAMI if test -n "$WHOAMI"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $WHOAMI" >&5 -$as_echo "$WHOAMI" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $WHOAMI" >&5 +printf "%s\n" "$WHOAMI" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3454,11 +3978,12 @@ if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_PKG_CONFIG+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKG_CONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. @@ -3468,11 +3993,15 @@ else for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3484,11 +4013,11 @@ esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 -$as_echo "$PKG_CONFIG" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 +printf "%s\n" "$PKG_CONFIG" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3497,11 +4026,12 @@ if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKG_CONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. @@ -3511,11 +4041,15 @@ else for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3527,11 +4061,11 @@ esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 -$as_echo "$ac_pt_PKG_CONFIG" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 +printf "%s\n" "$ac_pt_PKG_CONFIG" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then @@ -3539,8 +4073,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG @@ -3552,14 +4086,14 @@ fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 - { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 -$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 +printf %s "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } PKG_CONFIG="" fi fi @@ -3568,11 +4102,12 @@ fi if test -z "$PKG_CONFIG"; then # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_PKG_CONFIG+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKG_CONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. @@ -3582,11 +4117,15 @@ else for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3598,11 +4137,11 @@ esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 -$as_echo "$PKG_CONFIG" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 +printf "%s\n" "$PKG_CONFIG" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3623,12 +4162,13 @@ esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for X" >&5 -$as_echo_n "checking for X... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for X" >&5 +printf %s "checking for X... " >&6; } # Check whether --with-x was given. -if test "${with_x+set}" = set; then : +if test ${with_x+y} +then : withval=$with_x; fi @@ -3639,12 +4179,41 @@ if test "x$with_x" = xno; then else case $x_includes,$x_libraries in #( *\'*) as_fn_error $? "cannot use X directory names containing '" "$LINENO" 5;; #( - *,NONE | NONE,*) if ${ac_cv_have_x+:} false; then : - $as_echo_n "(cached) " >&6 -else + *,NONE | NONE,*) if test ${ac_cv_have_x+y} +then : + printf %s "(cached) " >&6 +else $as_nop # One or both of the vars are not set, and there is no cached value. -ac_x_includes=no ac_x_libraries=no -rm -f -r conftest.dir +ac_x_includes=no +ac_x_libraries=no +# Do we need to do anything special at all? +ac_save_LIBS=$LIBS +LIBS="-lX11 $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main (void) +{ +XrmInitialize () + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + # We can compile and link X programs with no special options. + ac_x_includes= + ac_x_libraries= +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS="$ac_save_LIBS" +# If that didn't work, only try xmkmf and file system searches +# for native compilation. +if test x"$ac_x_includes" = xno && test "$cross_compiling" = no +then : + rm -f -r conftest.dir if mkdir conftest.dir; then cd conftest.dir cat >Imakefile <<'_ACEOF' @@ -3683,7 +4252,7 @@ _ACEOF rm -f -r conftest.dir fi -# Standard set of common directories for X headers. + # Standard set of common directories for X headers. # Check X11 before X11Rn because it is often a symlink to the current release. ac_x_header_dirs=' /usr/X11/include @@ -3710,6 +4279,8 @@ ac_x_header_dirs=' /usr/local/include/X11R5 /usr/local/include/X11R4 +/opt/X11/include + /usr/X386/include /usr/x386/include /usr/XFree86/include/X11 @@ -3731,10 +4302,11 @@ if test "$ac_x_includes" = no; then /* end confdefs.h. */ #include _ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : +if ac_fn_c_try_cpp "$LINENO" +then : # We can compile using X headers with no special include directory. ac_x_includes= -else +else $as_nop for ac_dir in $ac_x_header_dirs; do if test -r "$ac_dir/X11/Xlib.h"; then ac_x_includes=$ac_dir @@ -3755,20 +4327,21 @@ if test "$ac_x_libraries" = no; then /* end confdefs.h. */ #include int -main () +main (void) { XrmInitialize () ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : LIBS=$ac_save_LIBS # We can link X programs with no special library path. ac_x_libraries= -else +else $as_nop LIBS=$ac_save_LIBS -for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` +for ac_dir in `printf "%s\n" "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` do # Don't even attempt the hair of trying to link an X program! for ac_extension in a so sl dylib la dll; do @@ -3779,19 +4352,21 @@ do done done fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi # $ac_x_libraries = no +fi +# Record the results. case $ac_x_includes,$ac_x_libraries in #( - no,* | *,no | *\'*) + no,* | *,no | *\'*) : # Didn't find X, or a directory has "'" in its name. - ac_cv_have_x="have_x=no";; #( - *) + ac_cv_have_x="have_x=no" ;; #( + *) : # Record where we found X for the cache. ac_cv_have_x="have_x=yes\ ac_x_includes='$ac_x_includes'\ - ac_x_libraries='$ac_x_libraries'" + ac_x_libraries='$ac_x_libraries'" ;; esac fi ;; #( @@ -3801,8 +4376,8 @@ fi fi # $with_x != no if test "$have_x" != yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5 -$as_echo "$have_x" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5 +printf "%s\n" "$have_x" >&6; } no_x=yes else # If each of the values was on the command line, it overrides each guess. @@ -3812,8 +4387,8 @@ else ac_cv_have_x="have_x=yes\ ac_x_includes='$x_includes'\ ac_x_libraries='$x_libraries'" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5 -$as_echo "libraries $x_libraries, headers $x_includes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5 +printf "%s\n" "libraries $x_libraries, headers $x_includes" >&6; } fi # Added for checking the existence of ungif. Note that # -gui uses the API of the underlying window system ONLY IF @@ -3857,11 +4432,12 @@ CPPFLAGS="$CPPFLAGS -I$GNUSTEP_HDIR" LDFLAGS="$LDFLAGS -L$GNUSTEP_LDIR/$LIBRARY_COMBO -L$GNUSTEP_LDIR" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lm" >&5 -$as_echo_n "checking for main in -lm... " >&6; } -if ${ac_cv_lib_m_main+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for main in -lm" >&5 +printf %s "checking for main in -lm... " >&6; } +if test ${ac_cv_lib_m_main+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lm $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -3869,372 +4445,150 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext int -main () +main (void) { return main (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_m_main=yes -else +else $as_nop ac_cv_lib_m_main=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_main" >&5 -$as_echo "$ac_cv_lib_m_main" >&6; } -if test "x$ac_cv_lib_m_main" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBM 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_main" >&5 +printf "%s\n" "$ac_cv_lib_m_main" >&6; } +if test "x$ac_cv_lib_m_main" = xyes +then : + printf "%s\n" "#define HAVE_LIBM 1" >>confdefs.h LIBS="-lm $LIBS" fi -for ac_func in rint rintf atan2f floorf -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF +ac_fn_c_check_func "$LINENO" "rint" "ac_cv_func_rint" +if test "x$ac_cv_func_rint" = xyes +then : + printf "%s\n" "#define HAVE_RINT 1" >>confdefs.h fi -done - +ac_fn_c_check_func "$LINENO" "rintf" "ac_cv_func_rintf" +if test "x$ac_cv_func_rintf" = xyes +then : + printf "%s\n" "#define HAVE_RINTF 1" >>confdefs.h +fi +ac_fn_c_check_func "$LINENO" "atan2f" "ac_cv_func_atan2f" +if test "x$ac_cv_func_atan2f" = xyes +then : + printf "%s\n" "#define HAVE_ATAN2F 1" >>confdefs.h -#-------------------------------------------------------------------- -# Support for determining mountpoints -#-------------------------------------------------------------------- -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -$as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if ${ac_cv_path_GREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$GREP"; then - ac_path_GREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in grep ggrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in -*GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_GREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_GREP=$GREP fi +ac_fn_c_check_func "$LINENO" "floorf" "ac_cv_func_floorf" +if test "x$ac_cv_func_floorf" = xyes +then : + printf "%s\n" "#define HAVE_FLOORF 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -$as_echo "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -$as_echo_n "checking for egrep... " >&6; } -if ${ac_cv_path_EGREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 - then ac_cv_path_EGREP="$GREP -E" - else - if test -z "$EGREP"; then - ac_path_EGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin + +#-------------------------------------------------------------------- +# Support for determining mountpoints +#-------------------------------------------------------------------- +ac_header= ac_cache= +for ac_item in $ac_header_c_list do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in egrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP" || continue -# Check for GNU ac_path_EGREP and select it if it is found. - # Check for GNU $ac_path_EGREP -case `"$ac_path_EGREP" --version 2>&1` in -*GNU*) - ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'EGREP' >> "conftest.nl" - "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_EGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP="$ac_path_EGREP" - ac_path_EGREP_max=$ac_count + if test $ac_cache; then + ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" + if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then + printf "%s\n" "#define $ac_item 1" >> confdefs.h fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_EGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_EGREP"; then - as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + ac_header= ac_cache= + elif test $ac_header; then + ac_cache=$ac_item + else + ac_header=$ac_item fi -else - ac_cv_path_EGREP=$EGREP -fi - - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -$as_echo "$ac_cv_path_EGREP" >&6; } - EGREP="$ac_cv_path_EGREP" - +done -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 -$as_echo_n "checking for ANSI C header files... " >&6; } -if ${ac_cv_header_stdc+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -#include -int -main () -{ - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_header_stdc=yes -else - ac_cv_header_stdc=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -if test $ac_cv_header_stdc = yes; then - # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then : -else - ac_cv_header_stdc=no -fi -rm -f conftest* -fi -if test $ac_cv_header_stdc = yes; then - # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include +if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes +then : -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then : +printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h -else - ac_cv_header_stdc=no fi -rm -f conftest* +ac_fn_c_check_header_compile "$LINENO" "mntent.h" "ac_cv_header_mntent_h" "$ac_includes_default" +if test "x$ac_cv_header_mntent_h" = xyes +then : + printf "%s\n" "#define HAVE_MNTENT_H 1" >>confdefs.h fi -if test $ac_cv_header_stdc = yes; then - # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then : - : -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#if ((' ' & 0x0FF) == 0x020) -# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#else -# define ISLOWER(c) \ - (('a' <= (c) && (c) <= 'i') \ - || ('j' <= (c) && (c) <= 'r') \ - || ('s' <= (c) && (c) <= 'z')) -# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) -#endif - -#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) -int -main () -{ - int i; - for (i = 0; i < 256; i++) - if (XOR (islower (i), ISLOWER (i)) - || toupper (i) != TOUPPER (i)) - return 2; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : +ac_fn_c_check_header_compile "$LINENO" "sys/mntent.h" "ac_cv_header_sys_mntent_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_mntent_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_MNTENT_H 1" >>confdefs.h -else - ac_cv_header_stdc=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext fi -fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 -$as_echo "$ac_cv_header_stdc" >&6; } -if test $ac_cv_header_stdc = yes; then - -$as_echo "#define STDC_HEADERS 1" >>confdefs.h - -fi - -# On IRIX 5.3, sys/types and inttypes.h are conflicting. -for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ - inttypes.h stdint.h unistd.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default -" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - -for ac_header in mntent.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "mntent.h" "ac_cv_header_mntent_h" "$ac_includes_default" -if test "x$ac_cv_header_mntent_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_MNTENT_H 1 -_ACEOF - -fi - -done - -for ac_header in sys/mntent.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "sys/mntent.h" "ac_cv_header_sys_mntent_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_mntent_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_SYS_MNTENT_H 1 -_ACEOF - -fi - -done - ac_fn_c_check_member "$LINENO" "struct mntent" "mnt_fsname" "ac_cv_member_struct_mntent_mnt_fsname" "#include " -if test "x$ac_cv_member_struct_mntent_mnt_fsname" = xyes; then : +if test "x$ac_cv_member_struct_mntent_mnt_fsname" = xyes +then : -$as_echo "#define MNT_FSNAME mnt_fsname" >>confdefs.h +printf "%s\n" "#define MNT_FSNAME mnt_fsname" >>confdefs.h fi ac_fn_c_check_member "$LINENO" "struct mntent" "mnt_fsname" "ac_cv_member_struct_mntent_mnt_fsname" "#include " -if test "x$ac_cv_member_struct_mntent_mnt_fsname" = xyes; then : +if test "x$ac_cv_member_struct_mntent_mnt_fsname" = xyes +then : -$as_echo "#define MNT_FSNAME mnt_fsname" >>confdefs.h +printf "%s\n" "#define MNT_FSNAME mnt_fsname" >>confdefs.h fi ac_fn_c_check_member "$LINENO" "struct mntent" "mnt_dir" "ac_cv_member_struct_mntent_mnt_dir" "#include " -if test "x$ac_cv_member_struct_mntent_mnt_dir" = xyes; then : +if test "x$ac_cv_member_struct_mntent_mnt_dir" = xyes +then : -$as_echo "#define MNT_MEMB mnt_dir" >>confdefs.h +printf "%s\n" "#define MNT_MEMB mnt_dir" >>confdefs.h fi ac_fn_c_check_member "$LINENO" "struct mntent" "mnt_mountp" "ac_cv_member_struct_mntent_mnt_mountp" "#include " -if test "x$ac_cv_member_struct_mntent_mnt_mountp" = xyes; then : +if test "x$ac_cv_member_struct_mntent_mnt_mountp" = xyes +then : -$as_echo "#define MNT_MEMB mnt_mountp" >>confdefs.h +printf "%s\n" "#define MNT_MEMB mnt_mountp" >>confdefs.h fi # getmntent is in the standard C library on UNICOS, in -lsun on Irix 4, # -lseq on Dynix/PTX, -lgen on Unixware. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing getmntent" >&5 -$as_echo_n "checking for library containing getmntent... " >&6; } -if ${ac_cv_search_getmntent+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing getmntent" >&5 +printf %s "checking for library containing getmntent... " >&6; } +if test ${ac_cv_search_getmntent+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -4242,113 +4596,93 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char getmntent (); int -main () +main (void) { return getmntent (); ; return 0; } _ACEOF -for ac_lib in '' sun seq gen; do +for ac_lib in '' sun seq gen +do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi - if ac_fn_c_try_link "$LINENO"; then : + if ac_fn_c_try_link "$LINENO" +then : ac_cv_search_getmntent=$ac_res fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext - if ${ac_cv_search_getmntent+:} false; then : + if test ${ac_cv_search_getmntent+y} +then : break fi done -if ${ac_cv_search_getmntent+:} false; then : +if test ${ac_cv_search_getmntent+y} +then : -else +else $as_nop ac_cv_search_getmntent=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_getmntent" >&5 -$as_echo "$ac_cv_search_getmntent" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_getmntent" >&5 +printf "%s\n" "$ac_cv_search_getmntent" >&6; } ac_res=$ac_cv_search_getmntent -if test "$ac_res" != no; then : +if test "$ac_res" != no +then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" ac_cv_func_getmntent=yes -$as_echo "#define HAVE_GETMNTENT 1" >>confdefs.h +printf "%s\n" "#define HAVE_GETMNTENT 1" >>confdefs.h -else +else $as_nop ac_cv_func_getmntent=no fi -for ac_func in getmntinfo -do : - ac_fn_c_check_func "$LINENO" "getmntinfo" "ac_cv_func_getmntinfo" -if test "x$ac_cv_func_getmntinfo" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_GETMNTINFO 1 -_ACEOF +ac_fn_c_check_func "$LINENO" "getmntinfo" "ac_cv_func_getmntinfo" +if test "x$ac_cv_func_getmntinfo" = xyes +then : + printf "%s\n" "#define HAVE_GETMNTINFO 1" >>confdefs.h fi -done -for ac_func in statfs -do : - ac_fn_c_check_func "$LINENO" "statfs" "ac_cv_func_statfs" -if test "x$ac_cv_func_statfs" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_STATFS 1 -_ACEOF +ac_fn_c_check_func "$LINENO" "statfs" "ac_cv_func_statfs" +if test "x$ac_cv_func_statfs" = xyes +then : + printf "%s\n" "#define HAVE_STATFS 1" >>confdefs.h fi -done -for ac_func in statvfs -do : - ac_fn_c_check_func "$LINENO" "statvfs" "ac_cv_func_statvfs" -if test "x$ac_cv_func_statvfs" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_STATVFS 1 -_ACEOF +ac_fn_c_check_func "$LINENO" "statvfs" "ac_cv_func_statvfs" +if test "x$ac_cv_func_statvfs" = xyes +then : + printf "%s\n" "#define HAVE_STATVFS 1" >>confdefs.h fi -done -for ac_header in sys/statvfs.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "sys/statvfs.h" "ac_cv_header_sys_statvfs_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_statvfs_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_SYS_STATVFS_H 1 -_ACEOF +ac_fn_c_check_header_compile "$LINENO" "sys/statvfs.h" "ac_cv_header_sys_statvfs_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_statvfs_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_STATVFS_H 1" >>confdefs.h fi -done - -for ac_header in sys/vfs.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "sys/vfs.h" "ac_cv_header_sys_vfs_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_vfs_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_SYS_VFS_H 1 -_ACEOF +ac_fn_c_check_header_compile "$LINENO" "sys/vfs.h" "ac_cv_header_sys_vfs_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_vfs_h" = xyes +then : + printf "%s\n" "#define HAVE_SYS_VFS_H 1" >>confdefs.h fi -done - ac_fn_c_check_member "$LINENO" "struct statfs" "f_flags" "ac_cv_member_struct_statfs_f_flags" " #if defined(HAVE_GETMNTINFO) @@ -4363,11 +4697,10 @@ ac_fn_c_check_member "$LINENO" "struct statfs" "f_flags" "ac_cv_member_struct_st #endif " -if test "x$ac_cv_member_struct_statfs_f_flags" = xyes; then : +if test "x$ac_cv_member_struct_statfs_f_flags" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_STATFS_F_FLAGS 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_STATFS_F_FLAGS 1" >>confdefs.h fi @@ -4384,11 +4717,10 @@ ac_fn_c_check_member "$LINENO" "struct statfs" "f_owner" "ac_cv_member_struct_st #endif " -if test "x$ac_cv_member_struct_statfs_f_owner" = xyes; then : +if test "x$ac_cv_member_struct_statfs_f_owner" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_STATFS_F_OWNER 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_STATFS_F_OWNER 1" >>confdefs.h fi @@ -4399,11 +4731,10 @@ ac_fn_c_check_member "$LINENO" "struct statvfs" "f_flag" "ac_cv_member_struct_st #endif " -if test "x$ac_cv_member_struct_statvfs_f_flag" = xyes; then : +if test "x$ac_cv_member_struct_statvfs_f_flag" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_STATVFS_F_FLAG 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_STATVFS_F_FLAG 1" >>confdefs.h fi @@ -4413,11 +4744,10 @@ ac_fn_c_check_member "$LINENO" "struct statvfs" "f_owner" "ac_cv_member_struct_s #endif " -if test "x$ac_cv_member_struct_statvfs_f_owner" = xyes; then : +if test "x$ac_cv_member_struct_statvfs_f_owner" = xyes +then : -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_STATVFS_F_OWNER 1 -_ACEOF +printf "%s\n" "#define HAVE_STRUCT_STATVFS_F_OWNER 1" >>confdefs.h fi @@ -4428,9 +4758,10 @@ fi #-------------------------------------------------------------------- # Check whether --with-include-flags was given. -if test "${with_include_flags+set}" = set; then : +if test ${with_include_flags+y} +then : withval=$with_include_flags; include_flags="$withval" -else +else $as_nop include_flags="no" fi @@ -4441,9 +4772,10 @@ fi # Check whether --with-library-flags was given. -if test "${with_library_flags+set}" = set; then : +if test ${with_library_flags+y} +then : withval=$with_library_flags; library_flags="$withval" -else +else $as_nop library_flags="no" fi @@ -4459,9 +4791,10 @@ GRAPHIC_CFLAGS= GRAPHIC_LFLAGS= # Check whether --enable-jpeg was given. -if test "${enable_jpeg+set}" = set; then : +if test ${enable_jpeg+y} +then : enableval=$enable_jpeg; -else +else $as_nop enable_jpeg=yes fi @@ -4469,17 +4802,19 @@ fi if test $enable_jpeg = yes; then # Check whether --with-jpeg_library was given. -if test "${with_jpeg_library+set}" = set; then : +if test ${with_jpeg_library+y} +then : withval=$with_jpeg_library; -else +else $as_nop with_jpeg_library= fi # Check whether --with-jpeg_include was given. -if test "${with_jpeg_include+set}" = set; then : +if test ${with_jpeg_include+y} +then : withval=$with_jpeg_include; -else +else $as_nop with_jpeg_include= fi @@ -4493,26 +4828,25 @@ fi CPPFLAGS="$with_jpeg_include ${CPPFLAGS}" LDFLAGS="$with_jpeg_library ${LDFLAGS}" - for ac_header in jpeglib.h + for ac_header in jpeglib.h do : - ac_fn_c_check_header_mongrel "$LINENO" "jpeglib.h" "ac_cv_header_jpeglib_h" "$ac_includes_default" -if test "x$ac_cv_header_jpeglib_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_JPEGLIB_H 1 -_ACEOF + ac_fn_c_check_header_compile "$LINENO" "jpeglib.h" "ac_cv_header_jpeglib_h" "$ac_includes_default" +if test "x$ac_cv_header_jpeglib_h" = xyes +then : + printf "%s\n" "#define HAVE_JPEGLIB_H 1" >>confdefs.h have_jpeg=yes -else +else $as_nop have_jpeg=no fi done - if test "$have_jpeg" = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for jpeg_destroy_decompress in -ljpeg" >&5 -$as_echo_n "checking for jpeg_destroy_decompress in -ljpeg... " >&6; } -if ${ac_cv_lib_jpeg_jpeg_destroy_decompress+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for jpeg_destroy_decompress in -ljpeg" >&5 +printf %s "checking for jpeg_destroy_decompress in -ljpeg... " >&6; } +if test ${ac_cv_lib_jpeg_jpeg_destroy_decompress+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-ljpeg $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -4521,33 +4855,30 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char jpeg_destroy_decompress (); int -main () +main (void) { return jpeg_destroy_decompress (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_jpeg_jpeg_destroy_decompress=yes -else +else $as_nop ac_cv_lib_jpeg_jpeg_destroy_decompress=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_jpeg_jpeg_destroy_decompress" >&5 -$as_echo "$ac_cv_lib_jpeg_jpeg_destroy_decompress" >&6; } -if test "x$ac_cv_lib_jpeg_jpeg_destroy_decompress" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBJPEG 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_jpeg_jpeg_destroy_decompress" >&5 +printf "%s\n" "$ac_cv_lib_jpeg_jpeg_destroy_decompress" >&6; } +if test "x$ac_cv_lib_jpeg_jpeg_destroy_decompress" = xyes +then : + printf "%s\n" "#define HAVE_LIBJPEG 1" >>confdefs.h LIBS="-ljpeg $LIBS" @@ -4575,17 +4906,19 @@ fi #-------------------------------------------------------------------- # Check whether --with-tiff_library was given. -if test "${with_tiff_library+set}" = set; then : +if test ${with_tiff_library+y} +then : withval=$with_tiff_library; -else +else $as_nop with_tiff_library= fi # Check whether --with-tiff_include was given. -if test "${with_tiff_include+set}" = set; then : +if test ${with_tiff_include+y} +then : withval=$with_tiff_include; -else +else $as_nop with_tiff_include= fi @@ -4599,11 +4932,12 @@ fi CPPFLAGS="$with_tiff_include ${CPPFLAGS}" LDFLAGS="$with_tiff_library ${LDFLAGS}" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lz" >&5 -$as_echo_n "checking for main in -lz... " >&6; } -if ${ac_cv_lib_z_main+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for main in -lz" >&5 +printf %s "checking for main in -lz... " >&6; } +if test ${ac_cv_lib_z_main+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lz $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -4611,47 +4945,48 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext int -main () +main (void) { return main (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_z_main=yes -else +else $as_nop ac_cv_lib_z_main=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_main" >&5 -$as_echo "$ac_cv_lib_z_main" >&6; } -if test "x$ac_cv_lib_z_main" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBZ 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_main" >&5 +printf "%s\n" "$ac_cv_lib_z_main" >&6; } +if test "x$ac_cv_lib_z_main" = xyes +then : + printf "%s\n" "#define HAVE_LIBZ 1" >>confdefs.h LIBS="-lz $LIBS" fi -ac_fn_c_check_header_mongrel "$LINENO" "tiffio.h" "ac_cv_header_tiffio_h" "$ac_includes_default" -if test "x$ac_cv_header_tiffio_h" = xyes; then : +ac_fn_c_check_header_compile "$LINENO" "tiffio.h" "ac_cv_header_tiffio_h" "$ac_includes_default" +if test "x$ac_cv_header_tiffio_h" = xyes +then : have_tiff=yes -else +else $as_nop have_tiff=no fi - if test "$have_tiff" = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for TIFFReadScanline in -ltiff" >&5 -$as_echo_n "checking for TIFFReadScanline in -ltiff... " >&6; } -if ${ac_cv_lib_tiff_TIFFReadScanline+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for TIFFReadScanline in -ltiff" >&5 +printf %s "checking for TIFFReadScanline in -ltiff... " >&6; } +if test ${ac_cv_lib_tiff_TIFFReadScanline+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-ltiff $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -4660,33 +4995,30 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char TIFFReadScanline (); int -main () +main (void) { return TIFFReadScanline (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_tiff_TIFFReadScanline=yes -else +else $as_nop ac_cv_lib_tiff_TIFFReadScanline=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tiff_TIFFReadScanline" >&5 -$as_echo "$ac_cv_lib_tiff_TIFFReadScanline" >&6; } -if test "x$ac_cv_lib_tiff_TIFFReadScanline" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBTIFF 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tiff_TIFFReadScanline" >&5 +printf "%s\n" "$ac_cv_lib_tiff_TIFFReadScanline" >&6; } +if test "x$ac_cv_lib_tiff_TIFFReadScanline" = xyes +then : + printf "%s\n" "#define HAVE_LIBTIFF 1" >>confdefs.h LIBS="-ltiff $LIBS" @@ -4698,17 +5030,17 @@ fi else pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libtiff-4" >&5 -$as_echo_n "checking for libtiff-4... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libtiff-4" >&5 +printf %s "checking for libtiff-4... " >&6; } if test -n "$TIFF_CFLAGS"; then pkg_cv_TIFF_CFLAGS="$TIFF_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtiff-4\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtiff-4\""; } >&5 ($PKG_CONFIG --exists --print-errors "libtiff-4") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_TIFF_CFLAGS=`$PKG_CONFIG --cflags "libtiff-4" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -4722,10 +5054,10 @@ if test -n "$TIFF_LIBS"; then pkg_cv_TIFF_LIBS="$TIFF_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtiff-4\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libtiff-4\""; } >&5 ($PKG_CONFIG --exists --print-errors "libtiff-4") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_TIFF_LIBS=`$PKG_CONFIG --libs "libtiff-4" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -4739,8 +5071,8 @@ fi if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes @@ -4759,16 +5091,16 @@ fi have_tiff=no elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } have_tiff=no else TIFF_CFLAGS=$pkg_cv_TIFF_CFLAGS TIFF_LIBS=$pkg_cv_TIFF_LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } GRAPHIC_LFLAGS="$TIFF_LIBS $GRAPHIC_LFLAGS" GRAPHIC_CFLAGS="$TIFF_CFLAGS $GRAPHIC_CFLAGS" @@ -4778,8 +5110,8 @@ fi fi if test "$have_tiff" = no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Cannot find libtiff header and/or library" >&5 -$as_echo "$as_me: WARNING: Cannot find libtiff header and/or library" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Cannot find libtiff header and/or library" >&5 +printf "%s\n" "$as_me: WARNING: Cannot find libtiff header and/or library" >&2;} echo "* The GUI library reqiures the TIFF library" echo "* Use --with-tiff-library to specify the tiff library" echo "* directory if it is not in the usual place(s)" @@ -4792,9 +5124,10 @@ fi # Find PNG #-------------------------------------------------------------------- # Check whether --enable-png was given. -if test "${enable_png+set}" = set; then : +if test ${enable_png+y} +then : enableval=$enable_png; -else +else $as_nop enable_png=yes fi @@ -4803,11 +5136,12 @@ if test $enable_png = yes; then # use libpng-config if available # Extract the first word of "libpng-config", so it can be a program name with args. set dummy libpng-config; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_HAVE_LIBPNG_CONFIG+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_HAVE_LIBPNG_CONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$HAVE_LIBPNG_CONFIG"; then ac_cv_prog_HAVE_LIBPNG_CONFIG="$HAVE_LIBPNG_CONFIG" # Let the user override the test. else @@ -4815,11 +5149,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_HAVE_LIBPNG_CONFIG="yes" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4830,11 +5168,11 @@ fi fi HAVE_LIBPNG_CONFIG=$ac_cv_prog_HAVE_LIBPNG_CONFIG if test -n "$HAVE_LIBPNG_CONFIG"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_LIBPNG_CONFIG" >&5 -$as_echo "$HAVE_LIBPNG_CONFIG" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $HAVE_LIBPNG_CONFIG" >&5 +printf "%s\n" "$HAVE_LIBPNG_CONFIG" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -4843,23 +5181,19 @@ fi PNG_LDFLAGS="`libpng-config --ldflags`" CPPFLAGS="${CPPFLAGS} $PNG_CFLAGS" LDFLAGS="$PNG_LDFLAGS ${LDFLAGS}" - for ac_header in png.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "png.h" "ac_cv_header_png_h" "$ac_includes_default" -if test "x$ac_cv_header_png_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_PNG_H 1 -_ACEOF + ac_fn_c_check_header_compile "$LINENO" "png.h" "ac_cv_header_png_h" "$ac_includes_default" +if test "x$ac_cv_header_png_h" = xyes +then : + printf "%s\n" "#define HAVE_PNG_H 1" >>confdefs.h fi -done - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for png_sig_cmp in -lpng" >&5 -$as_echo_n "checking for png_sig_cmp in -lpng... " >&6; } -if ${ac_cv_lib_png_png_sig_cmp+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for png_sig_cmp in -lpng" >&5 +printf %s "checking for png_sig_cmp in -lpng... " >&6; } +if test ${ac_cv_lib_png_png_sig_cmp+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lpng $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -4868,33 +5202,30 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char png_sig_cmp (); int -main () +main (void) { return png_sig_cmp (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_png_png_sig_cmp=yes -else +else $as_nop ac_cv_lib_png_png_sig_cmp=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_png_png_sig_cmp" >&5 -$as_echo "$ac_cv_lib_png_png_sig_cmp" >&6; } -if test "x$ac_cv_lib_png_png_sig_cmp" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBPNG 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_png_png_sig_cmp" >&5 +printf "%s\n" "$ac_cv_lib_png_png_sig_cmp" >&6; } +if test "x$ac_cv_lib_png_png_sig_cmp" = xyes +then : + printf "%s\n" "#define HAVE_LIBPNG 1" >>confdefs.h LIBS="-lpng $LIBS" @@ -4903,29 +5234,25 @@ fi if test "$ac_cv_search_png_sig_cmp" != no; then GRAPHIC_CFLAGS="$PNG_CFLAGS $GRAPHIC_CFLAGS" GRAPHIC_LFLAGS="$PNG_LDFLAGS $GRAPHIC_LFLAGS" - $as_echo "#define HAVE_LIBPNG 1" >>confdefs.h + printf "%s\n" "#define HAVE_LIBPNG 1" >>confdefs.h fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Can't find libpng-config, guessing required headers and libraries." >&5 -$as_echo "$as_me: WARNING: Can't find libpng-config, guessing required headers and libraries." >&2;} - for ac_header in png.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "png.h" "ac_cv_header_png_h" "$ac_includes_default" -if test "x$ac_cv_header_png_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_PNG_H 1 -_ACEOF + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Can't find libpng-config, guessing required headers and libraries." >&5 +printf "%s\n" "$as_me: WARNING: Can't find libpng-config, guessing required headers and libraries." >&2;} + ac_fn_c_check_header_compile "$LINENO" "png.h" "ac_cv_header_png_h" "$ac_includes_default" +if test "x$ac_cv_header_png_h" = xyes +then : + printf "%s\n" "#define HAVE_PNG_H 1" >>confdefs.h fi -done - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for png_sig_cmp in -lpng" >&5 -$as_echo_n "checking for png_sig_cmp in -lpng... " >&6; } -if ${ac_cv_lib_png_png_sig_cmp+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for png_sig_cmp in -lpng" >&5 +printf %s "checking for png_sig_cmp in -lpng... " >&6; } +if test ${ac_cv_lib_png_png_sig_cmp+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lpng $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -4934,33 +5261,30 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char png_sig_cmp (); int -main () +main (void) { return png_sig_cmp (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_png_png_sig_cmp=yes -else +else $as_nop ac_cv_lib_png_png_sig_cmp=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_png_png_sig_cmp" >&5 -$as_echo "$ac_cv_lib_png_png_sig_cmp" >&6; } -if test "x$ac_cv_lib_png_png_sig_cmp" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBPNG 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_png_png_sig_cmp" >&5 +printf "%s\n" "$ac_cv_lib_png_png_sig_cmp" >&6; } +if test "x$ac_cv_lib_png_png_sig_cmp" = xyes +then : + printf "%s\n" "#define HAVE_LIBPNG 1" >>confdefs.h LIBS="-lpng $LIBS" @@ -4983,16 +5307,18 @@ fi # Find additional image libs #-------------------------------------------------------------------- # Check whether --enable-ungif was given. -if test "${enable_ungif+set}" = set; then : +if test ${enable_ungif+y} +then : enableval=$enable_ungif; -else +else $as_nop enable_ungif=yes fi # Check whether --enable-libgif was given. -if test "${enable_libgif+set}" = set; then : +if test ${enable_libgif+y} +then : enableval=$enable_libgif; -else +else $as_nop enable_libgif=no fi @@ -5002,11 +5328,12 @@ fi have_ungif=no if test "${enable_ungif}" = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DGifOpen in -lungif" >&5 -$as_echo_n "checking for DGifOpen in -lungif... " >&6; } -if ${ac_cv_lib_ungif_DGifOpen+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for DGifOpen in -lungif" >&5 +printf %s "checking for DGifOpen in -lungif... " >&6; } +if test ${ac_cv_lib_ungif_DGifOpen+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lungif $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -5015,33 +5342,30 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char DGifOpen (); int -main () +main (void) { return DGifOpen (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_ungif_DGifOpen=yes -else +else $as_nop ac_cv_lib_ungif_DGifOpen=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ungif_DGifOpen" >&5 -$as_echo "$ac_cv_lib_ungif_DGifOpen" >&6; } -if test "x$ac_cv_lib_ungif_DGifOpen" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBUNGIF 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ungif_DGifOpen" >&5 +printf "%s\n" "$ac_cv_lib_ungif_DGifOpen" >&6; } +if test "x$ac_cv_lib_ungif_DGifOpen" = xyes +then : + printf "%s\n" "#define HAVE_LIBUNGIF 1" >>confdefs.h LIBS="-lungif $LIBS" @@ -5055,8 +5379,8 @@ fi orig_CPPFLAGS="${CPPFLAGS}" orig_LDFLAGS="${LDFLAGS}" orig_LIBS="${LIBS}" - { $as_echo "$as_me:${as_lineno-$LINENO}: Checking if ungif is linked against -lX11" >&5 -$as_echo "$as_me: Checking if ungif is linked against -lX11" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Checking if ungif is linked against -lX11" >&5 +printf "%s\n" "$as_me: Checking if ungif is linked against -lX11" >&6;} # This implies either that ungif is not installed at all, or that it # explicitly refers to the symbols defined in X11. Now see if the latter # is the case. @@ -5064,11 +5388,12 @@ $as_echo "$as_me: Checking if ungif is linked against -lX11" >&6;} LDFLAGS="${LDFLAGS} -L${ac_x_libraries}" LIBS="${LIBS} -lX11" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DGifCloseFile in -lungif" >&5 -$as_echo_n "checking for DGifCloseFile in -lungif... " >&6; } -if ${ac_cv_lib_ungif_DGifCloseFile+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for DGifCloseFile in -lungif" >&5 +printf %s "checking for DGifCloseFile in -lungif... " >&6; } +if test ${ac_cv_lib_ungif_DGifCloseFile+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lungif $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -5077,33 +5402,30 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char DGifCloseFile (); int -main () +main (void) { return DGifCloseFile (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_ungif_DGifCloseFile=yes -else +else $as_nop ac_cv_lib_ungif_DGifCloseFile=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ungif_DGifCloseFile" >&5 -$as_echo "$ac_cv_lib_ungif_DGifCloseFile" >&6; } -if test "x$ac_cv_lib_ungif_DGifCloseFile" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBUNGIF 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ungif_DGifCloseFile" >&5 +printf "%s\n" "$ac_cv_lib_ungif_DGifCloseFile" >&6; } +if test "x$ac_cv_lib_ungif_DGifCloseFile" = xyes +then : + printf "%s\n" "#define HAVE_LIBUNGIF 1" >>confdefs.h LIBS="-lungif $LIBS" @@ -5119,8 +5441,8 @@ fi # This indicates ungif actually refers to the X11's symbols. We modify # the flags so that -gui gets linked against the X11 library to support # ungif. - { $as_echo "$as_me:${as_lineno-$LINENO}: -gui will be linked against -lX11 to support ungif images" >&5 -$as_echo "$as_me: -gui will be linked against -lX11 to support ungif images" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -gui will be linked against -lX11 to support ungif images" >&5 +printf "%s\n" "$as_me: -gui will be linked against -lX11 to support ungif images" >&6;} GRAPHIC_CFLAGS="-I${ac_x_includes} $GRAPHIC_CFLAGS" GRAPHIC_LFLAGS="-L${ac_x_libraries} $GRAPHIC_LFLAGS" have_ungif=yes @@ -5129,11 +5451,12 @@ $as_echo "$as_me: -gui will be linked against -lX11 to support ungif images" >&6 fi if test "$have_ungif" = no -o "${enable_libgif}" = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DGifOpen in -lgif" >&5 -$as_echo_n "checking for DGifOpen in -lgif... " >&6; } -if ${ac_cv_lib_gif_DGifOpen+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for DGifOpen in -lgif" >&5 +printf %s "checking for DGifOpen in -lgif... " >&6; } +if test ${ac_cv_lib_gif_DGifOpen+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lgif $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -5142,33 +5465,30 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char DGifOpen (); int -main () +main (void) { return DGifOpen (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_gif_DGifOpen=yes -else +else $as_nop ac_cv_lib_gif_DGifOpen=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gif_DGifOpen" >&5 -$as_echo "$ac_cv_lib_gif_DGifOpen" >&6; } -if test "x$ac_cv_lib_gif_DGifOpen" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBGIF 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gif_DGifOpen" >&5 +printf "%s\n" "$ac_cv_lib_gif_DGifOpen" >&6; } +if test "x$ac_cv_lib_gif_DGifOpen" = xyes +then : + printf "%s\n" "#define HAVE_LIBGIF 1" >>confdefs.h LIBS="-lgif $LIBS" @@ -5179,8 +5499,8 @@ fi orig_CPPFLAGS="${CPPFLAGS}" orig_LDFLAGS="${LDFLAGS}" orig_LIBS="${LIBS}" - { $as_echo "$as_me:${as_lineno-$LINENO}: Checking if libgif is linked against -lX11" >&5 -$as_echo "$as_me: Checking if libgif is linked against -lX11" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Checking if libgif is linked against -lX11" >&5 +printf "%s\n" "$as_me: Checking if libgif is linked against -lX11" >&6;} # This implies either that libgif is not installed at all, or that it # explicitly refers to the symbols defined in X11. Now see if the latter # is the case. @@ -5188,11 +5508,12 @@ $as_echo "$as_me: Checking if libgif is linked against -lX11" >&6;} LDFLAGS="${LDFLAGS} -L${ac_x_libraries}" LIBS="${LIBS} -lX11" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DGifCloseFile in -lgif" >&5 -$as_echo_n "checking for DGifCloseFile in -lgif... " >&6; } -if ${ac_cv_lib_gif_DGifCloseFile+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for DGifCloseFile in -lgif" >&5 +printf %s "checking for DGifCloseFile in -lgif... " >&6; } +if test ${ac_cv_lib_gif_DGifCloseFile+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lgif $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -5201,33 +5522,30 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char DGifCloseFile (); int -main () +main (void) { return DGifCloseFile (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_gif_DGifCloseFile=yes -else +else $as_nop ac_cv_lib_gif_DGifCloseFile=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gif_DGifCloseFile" >&5 -$as_echo "$ac_cv_lib_gif_DGifCloseFile" >&6; } -if test "x$ac_cv_lib_gif_DGifCloseFile" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBGIF 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gif_DGifCloseFile" >&5 +printf "%s\n" "$ac_cv_lib_gif_DGifCloseFile" >&6; } +if test "x$ac_cv_lib_gif_DGifCloseFile" = xyes +then : + printf "%s\n" "#define HAVE_LIBGIF 1" >>confdefs.h LIBS="-lgif $LIBS" @@ -5243,8 +5561,8 @@ fi # This indicates libgif actually refers to the X11's symbols. We modify # the flags so that -gui gets linked against the X11 library to support # libgif. - { $as_echo "$as_me:${as_lineno-$LINENO}: -gui will be linked against -lX11 to support libgif images" >&5 -$as_echo "$as_me: -gui will be linked against -lX11 to support libgif images" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: -gui will be linked against -lX11 to support libgif images" >&5 +printf "%s\n" "$as_me: -gui will be linked against -lX11 to support libgif images" >&6;} GRAPHIC_CFLAGS="-I${ac_x_includes} $GRAPHIC_CFLAGS" GRAPHIC_LFLAGS="-L${ac_x_libraries} $GRAPHIC_LFLAGS" fi @@ -5254,27 +5572,19 @@ fi # QuantizeBuffer was removed from giflib in version 4.2 but was reintroduced # in the 5.0 release with a new name. If this function is not present # we disable the support to create gif image representations. -for ac_func in QuantizeBuffer -do : - ac_fn_c_check_func "$LINENO" "QuantizeBuffer" "ac_cv_func_QuantizeBuffer" -if test "x$ac_cv_func_QuantizeBuffer" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_QUANTIZEBUFFER 1 -_ACEOF +ac_fn_c_check_func "$LINENO" "QuantizeBuffer" "ac_cv_func_QuantizeBuffer" +if test "x$ac_cv_func_QuantizeBuffer" = xyes +then : + printf "%s\n" "#define HAVE_QUANTIZEBUFFER 1" >>confdefs.h fi -done -for ac_func in GifQuantizeBuffer -do : - ac_fn_c_check_func "$LINENO" "GifQuantizeBuffer" "ac_cv_func_GifQuantizeBuffer" -if test "x$ac_cv_func_GifQuantizeBuffer" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_GIFQUANTIZEBUFFER 1 -_ACEOF +ac_fn_c_check_func "$LINENO" "GifQuantizeBuffer" "ac_cv_func_GifQuantizeBuffer" +if test "x$ac_cv_func_GifQuantizeBuffer" = xyes +then : + printf "%s\n" "#define HAVE_GIFQUANTIZEBUFFER 1" >>confdefs.h fi -done #-------------------------------------------------------------------- @@ -5282,25 +5592,27 @@ done #-------------------------------------------------------------------- # Check whether --enable-imagemagick was given. -if test "${enable_imagemagick+set}" = set; then : +if test ${enable_imagemagick+y} +then : enableval=$enable_imagemagick; fi -if test "x$enable_imagemagick" = "xyes"; then : +if test "x$enable_imagemagick" = "xyes" +then : pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for MagickCore" >&5 -$as_echo_n "checking for MagickCore... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MagickCore" >&5 +printf %s "checking for MagickCore... " >&6; } if test -n "$IMAGEMAGICK_CFLAGS"; then pkg_cv_IMAGEMAGICK_CFLAGS="$IMAGEMAGICK_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"MagickCore\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"MagickCore\""; } >&5 ($PKG_CONFIG --exists --print-errors "MagickCore") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_IMAGEMAGICK_CFLAGS=`$PKG_CONFIG --cflags "MagickCore" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -5314,10 +5626,10 @@ if test -n "$IMAGEMAGICK_LIBS"; then pkg_cv_IMAGEMAGICK_LIBS="$IMAGEMAGICK_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"MagickCore\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"MagickCore\""; } >&5 ($PKG_CONFIG --exists --print-errors "MagickCore") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_IMAGEMAGICK_LIBS=`$PKG_CONFIG --libs "MagickCore" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -5331,8 +5643,8 @@ fi if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes @@ -5348,44 +5660,45 @@ fi echo "$IMAGEMAGICK_PKG_ERRORS" >&5 -$as_echo "#define HAVE_IMAGEMAGICK 0" >>confdefs.h +printf "%s\n" "#define HAVE_IMAGEMAGICK 0" >>confdefs.h elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } -$as_echo "#define HAVE_IMAGEMAGICK 0" >>confdefs.h +printf "%s\n" "#define HAVE_IMAGEMAGICK 0" >>confdefs.h else IMAGEMAGICK_CFLAGS=$pkg_cv_IMAGEMAGICK_CFLAGS IMAGEMAGICK_LIBS=$pkg_cv_IMAGEMAGICK_LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } GRAPHIC_CFLAGS="$IMAGEMAGICK_CFLAGS $GRAPHIC_CFLAGS" GRAPHIC_LFLAGS="$IMAGEMAGICK_LIBS $GRAPHIC_LFLAGS" -$as_echo "#define HAVE_IMAGEMAGICK 1" >>confdefs.h +printf "%s\n" "#define HAVE_IMAGEMAGICK 1" >>confdefs.h fi fi -if test "x$enable_imagemagick" = "xyes"; then : +if test "x$enable_imagemagick" = "xyes" +then : pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for MagickCore >= 7" >&5 -$as_echo_n "checking for MagickCore >= 7... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MagickCore >= 7" >&5 +printf %s "checking for MagickCore >= 7... " >&6; } if test -n "$MAGICKCORE_CFLAGS"; then pkg_cv_MAGICKCORE_CFLAGS="$MAGICKCORE_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"MagickCore >= 7\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"MagickCore >= 7\""; } >&5 ($PKG_CONFIG --exists --print-errors "MagickCore >= 7") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_MAGICKCORE_CFLAGS=`$PKG_CONFIG --cflags "MagickCore >= 7" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -5399,10 +5712,10 @@ if test -n "$MAGICKCORE_LIBS"; then pkg_cv_MAGICKCORE_LIBS="$MAGICKCORE_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"MagickCore >= 7\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"MagickCore >= 7\""; } >&5 ($PKG_CONFIG --exists --print-errors "MagickCore >= 7") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_MAGICKCORE_LIBS=`$PKG_CONFIG --libs "MagickCore >= 7" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -5416,8 +5729,8 @@ fi if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes @@ -5433,21 +5746,21 @@ fi echo "$MAGICKCORE_PKG_ERRORS" >&5 -$as_echo "#define MAGICKCORE_7_OR_NEWER 0" >>confdefs.h +printf "%s\n" "#define MAGICKCORE_7_OR_NEWER 0" >>confdefs.h elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } -$as_echo "#define MAGICKCORE_7_OR_NEWER 0" >>confdefs.h +printf "%s\n" "#define MAGICKCORE_7_OR_NEWER 0" >>confdefs.h else MAGICKCORE_CFLAGS=$pkg_cv_MAGICKCORE_CFLAGS MAGICKCORE_LIBS=$pkg_cv_MAGICKCORE_LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } -$as_echo "#define MAGICKCORE_7_OR_NEWER 1" >>confdefs.h +printf "%s\n" "#define MAGICKCORE_7_OR_NEWER 1" >>confdefs.h fi @@ -5459,23 +5772,26 @@ fi #-------------------------------------------------------------------- HAVE_ICU=0 # Check whether --enable-icu was given. -if test "${enable_icu+set}" = set; then : +if test ${enable_icu+y} +then : enableval=$enable_icu; -else +else $as_nop enable_icu=yes fi # Check whether --with-icu-library was given. -if test "${with_icu_library+set}" = set; then : +if test ${with_icu_library+y} +then : withval=$with_icu_library; icu_libdir="$withval" -else +else $as_nop icu_libdir="no" fi -if test "x$enable_icu" = "xyes"; then : +if test "x$enable_icu" = "xyes" +then : # First attempt, icu-config @@ -5484,11 +5800,12 @@ if test "x$enable_icu" = "xyes"; then : if test -z "$ICU_CONFIG"; then # Extract the first word of "icu-config", so it can be a program name with args. set dummy icu-config; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_ICU_CONFIG+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ICU_CONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop case $ICU_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ICU_CONFIG="$ICU_CONFIG" # Let the user override the test with a path. @@ -5498,11 +5815,15 @@ else for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_ICU_CONFIG="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ICU_CONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -5515,11 +5836,11 @@ esac fi ICU_CONFIG=$ac_cv_path_ICU_CONFIG if test -n "$ICU_CONFIG"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ICU_CONFIG" >&5 -$as_echo "$ICU_CONFIG" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ICU_CONFIG" >&5 +printf "%s\n" "$ICU_CONFIG" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -5531,24 +5852,24 @@ fi echo "See http://site.icu-project.org/ for help." else ICU_VERSION=`$ICU_CONFIG --version` - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ICU >= 4.0" >&5 -$as_echo_n "checking for ICU >= 4.0... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ICU >= 4.0" >&5 +printf %s "checking for ICU >= 4.0... " >&6; } found=`expr $ICU_VERSION \>= 4.0` if test "$found" = "1" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } ok=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: checking ICU_LIBS" >&5 -$as_echo_n "checking ICU_LIBS... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking ICU_LIBS" >&5 +printf %s "checking ICU_LIBS... " >&6; } ICU_LIBS=`$ICU_CONFIG --ldflags-libsonly` - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ICU_LIBS" >&5 -$as_echo "$ICU_LIBS" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking ICU_LDFLAGS" >&5 -$as_echo_n "checking ICU_LDFLAGS... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ICU_LIBS" >&5 +printf "%s\n" "$ICU_LIBS" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking ICU_LDFLAGS" >&5 +printf %s "checking ICU_LDFLAGS... " >&6; } ICU_LDFLAGS=`$ICU_CONFIG --ldflags-searchpath` - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ICU_LDFLAGS" >&5 -$as_echo "$ICU_LDFLAGS" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ICU_LDFLAGS" >&5 +printf "%s\n" "$ICU_LDFLAGS" >&6; } else ICU_LIBS="" ICU_LDFLAGS="" @@ -5570,17 +5891,17 @@ $as_echo "$ICU_LDFLAGS" >&6; } if test $HAVE_ICU = 0; then pkg_failed=no -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for icu-i18n > 49.0" >&5 -$as_echo_n "checking for icu-i18n > 49.0... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for icu-i18n > 49.0" >&5 +printf %s "checking for icu-i18n > 49.0... " >&6; } if test -n "$ICU_CFLAGS"; then pkg_cv_ICU_CFLAGS="$ICU_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"icu-i18n > 49.0\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"icu-i18n > 49.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "icu-i18n > 49.0") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_ICU_CFLAGS=`$PKG_CONFIG --cflags "icu-i18n > 49.0" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -5594,10 +5915,10 @@ if test -n "$ICU_LIBS"; then pkg_cv_ICU_LIBS="$ICU_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"icu-i18n > 49.0\""; } >&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"icu-i18n > 49.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "icu-i18n > 49.0") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_ICU_LIBS=`$PKG_CONFIG --libs "icu-i18n > 49.0" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes @@ -5611,8 +5932,8 @@ fi if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes @@ -5629,35 +5950,35 @@ fi HAVE_ICU=0 elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } HAVE_ICU=0 else ICU_CFLAGS=$pkg_cv_ICU_CFLAGS ICU_LIBS=$pkg_cv_ICU_LIBS - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } - for ac_header in unicode/uloc.h unicode/ulocdata.h unicode/ucol.h unicode/ucurr.h unicode/uregex.h unicode/ucal.h unicode/unorm2.h unicode/unum.h unicode/udat.h unicode/udatpg.h unicode/ustring.h unicode/usearch.h unicode/ucnv.h unicode/utext.h unicode/ubrk.h unicode/utypes.h + for ac_header in unicode/uloc.h unicode/ulocdata.h unicode/ucol.h unicode/ucurr.h unicode/uregex.h unicode/ucal.h unicode/unorm2.h unicode/unum.h unicode/udat.h unicode/udatpg.h unicode/ustring.h unicode/usearch.h unicode/ucnv.h unicode/utext.h unicode/ubrk.h unicode/utypes.h do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + as_ac_Header=`printf "%s\n" "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes" +then : cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +#define `printf "%s\n" "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF HAVE_ICU=1 fi done - fi fi if test $HAVE_ICU = 0; then HAVE_ICU=0; - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libicu (icu-config disabled)..." >&5 -$as_echo "$as_me: checking for libicu (icu-config disabled)..." >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libicu (icu-config disabled)..." >&5 +printf "%s\n" "$as_me: checking for libicu (icu-config disabled)..." >&6;} if test "$icu_libdir" != "no"; then ICU_LDFLAGS="-L$icu_libdir"; fi @@ -5667,19 +5988,20 @@ $as_echo "$as_me: checking for libicu (icu-config disabled)..." >&6;} /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : HAVE_ICU=1 -else +else $as_nop HAVE_ICU=0 fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext; LDFLAGS="$saved_LDFLAGS"; ICU_LIBS="-licui18n -licuuc -licudata -lm" @@ -5687,28 +6009,28 @@ rm -f core conftest.err conftest.$ac_objext \ if test $HAVE_ICU = 1; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - for ac_header in unicode/uchar.h unicode/ustring.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + ac_fn_c_check_header_compile "$LINENO" "unicode/uchar.h" "ac_cv_header_unicode_uchar_h" "$ac_includes_default" +if test "x$ac_cv_header_unicode_uchar_h" = xyes +then : + printf "%s\n" "#define HAVE_UNICODE_UCHAR_H 1" >>confdefs.h fi +ac_fn_c_check_header_compile "$LINENO" "unicode/ustring.h" "ac_cv_header_unicode_ustring_h" "$ac_includes_default" +if test "x$ac_cv_header_unicode_ustring_h" = xyes +then : + printf "%s\n" "#define HAVE_UNICODE_USTRING_H 1" >>confdefs.h -done +fi GRAPHIC_LFLAGS="$ICU_LDFLAGS $ICU_LIBS $GRAPHIC_LFLAGS" HAVE_ICU=1 else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: The International Components for Unicode (ICU) development headers and libraries do not appear to be available on this system." >&5 -$as_echo "$as_me: WARNING: The International Components for Unicode (ICU) development headers and libraries do not appear to be available on this system." >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: The International Components for Unicode (ICU) development headers and libraries do not appear to be available on this system." >&5 +printf "%s\n" "$as_me: WARNING: The International Components for Unicode (ICU) development headers and libraries do not appear to be available on this system." >&2;} fi fi @@ -5720,18 +6042,20 @@ fi # Apple's libobjc.A, screwing up the links to the GNU libobjc. #-------------------------------------------------------------------- # Check whether --enable-aspell was given. -if test "${enable_aspell+set}" = set; then : +if test ${enable_aspell+y} +then : enableval=$enable_aspell; -else +else $as_nop enable_aspell=yes fi if test "$enable_aspell" = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for new_aspell_document_checker in -laspell" >&5 -$as_echo_n "checking for new_aspell_document_checker in -laspell... " >&6; } -if ${ac_cv_lib_aspell_new_aspell_document_checker+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for new_aspell_document_checker in -laspell" >&5 +printf %s "checking for new_aspell_document_checker in -laspell... " >&6; } +if test ${ac_cv_lib_aspell_new_aspell_document_checker+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-laspell $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -5740,33 +6064,30 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char new_aspell_document_checker (); int -main () +main (void) { return new_aspell_document_checker (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_aspell_new_aspell_document_checker=yes -else +else $as_nop ac_cv_lib_aspell_new_aspell_document_checker=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_aspell_new_aspell_document_checker" >&5 -$as_echo "$ac_cv_lib_aspell_new_aspell_document_checker" >&6; } -if test "x$ac_cv_lib_aspell_new_aspell_document_checker" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBASPELL 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_aspell_new_aspell_document_checker" >&5 +printf "%s\n" "$ac_cv_lib_aspell_new_aspell_document_checker" >&6; } +if test "x$ac_cv_lib_aspell_new_aspell_document_checker" = xyes +then : + printf "%s\n" "#define HAVE_LIBASPELL 1" >>confdefs.h LIBS="-laspell $LIBS" @@ -5774,31 +6095,27 @@ fi fi if test "${ac_cv_lib_aspell_new_aspell_document_checker}" = yes; then - for ac_header in aspell.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "aspell.h" "ac_cv_header_aspell_h" "$ac_includes_default" -if test "x$ac_cv_header_aspell_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_ASPELL_H 1 -_ACEOF + ac_fn_c_check_header_compile "$LINENO" "aspell.h" "ac_cv_header_aspell_h" "$ac_includes_default" +if test "x$ac_cv_header_aspell_h" = xyes +then : + printf "%s\n" "#define HAVE_ASPELL_H 1" >>confdefs.h fi -done - -$as_echo "#define HAVE_ASPELL 1" >>confdefs.h +printf "%s\n" "#define HAVE_ASPELL 1" >>confdefs.h fi #-------------------------------------------------------------------- # Check for ICNS library. #-------------------------------------------------------------------- -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for icns_read_family_from_file in -licns" >&5 -$as_echo_n "checking for icns_read_family_from_file in -licns... " >&6; } -if ${ac_cv_lib_icns_icns_read_family_from_file+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for icns_read_family_from_file in -licns" >&5 +printf %s "checking for icns_read_family_from_file in -licns... " >&6; } +if test ${ac_cv_lib_icns_icns_read_family_from_file+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-licns $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -5807,33 +6124,30 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char icns_read_family_from_file (); int -main () +main (void) { return icns_read_family_from_file (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_icns_icns_read_family_from_file=yes -else +else $as_nop ac_cv_lib_icns_icns_read_family_from_file=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_icns_icns_read_family_from_file" >&5 -$as_echo "$ac_cv_lib_icns_icns_read_family_from_file" >&6; } -if test "x$ac_cv_lib_icns_icns_read_family_from_file" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBICNS 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_icns_icns_read_family_from_file" >&5 +printf "%s\n" "$ac_cv_lib_icns_icns_read_family_from_file" >&6; } +if test "x$ac_cv_lib_icns_icns_read_family_from_file" = xyes +then : + printf "%s\n" "#define HAVE_LIBICNS 1" >>confdefs.h LIBS="-licns $LIBS" @@ -5844,43 +6158,40 @@ fi # NSSound #-------------------------------------------------------------------- # Check whether --enable-sound was given. -if test "${enable_sound+set}" = set; then : +if test ${enable_sound+y} +then : enableval=$enable_sound; -else +else $as_nop enable_sound=yes fi # Initialize to nothing... BUILD_SOUND= # Check for the headers... -for ac_header in sndfile.h + for ac_header in sndfile.h do : - ac_fn_c_check_header_mongrel "$LINENO" "sndfile.h" "ac_cv_header_sndfile_h" "$ac_includes_default" -if test "x$ac_cv_header_sndfile_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_SNDFILE_H 1 -_ACEOF + ac_fn_c_check_header_compile "$LINENO" "sndfile.h" "ac_cv_header_sndfile_h" "$ac_includes_default" +if test "x$ac_cv_header_sndfile_h" = xyes +then : + printf "%s\n" "#define HAVE_SNDFILE_H 1" >>confdefs.h have_sndfile=yes -else +else $as_nop have_sndfile=no fi done - -for ac_header in ao/ao.h + for ac_header in ao/ao.h do : - ac_fn_c_check_header_mongrel "$LINENO" "ao/ao.h" "ac_cv_header_ao_ao_h" "$ac_includes_default" -if test "x$ac_cv_header_ao_ao_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_AO_AO_H 1 -_ACEOF + ac_fn_c_check_header_compile "$LINENO" "ao/ao.h" "ac_cv_header_ao_ao_h" "$ac_includes_default" +if test "x$ac_cv_header_ao_ao_h" = xyes +then : + printf "%s\n" "#define HAVE_AO_AO_H 1" >>confdefs.h have_ao=yes -else +else $as_nop have_ao=no fi done - # Only if we have both... if test $have_sndfile = yes -a $have_ao = yes -a $enable_sound = yes; then BUILD_SOUND="sound" @@ -5891,20 +6202,22 @@ fi # NSSpeechSynthesizer #-------------------------------------------------------------------- # Check whether --enable-speech was given. -if test "${enable_speech+set}" = set; then : +if test ${enable_speech+y} +then : enableval=$enable_speech; -else +else $as_nop enable_speech=yes fi BUILD_SPEECH= # has flite, for speech synthesis. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for new_utterance in -lflite" >&5 -$as_echo_n "checking for new_utterance in -lflite... " >&6; } -if ${ac_cv_lib_flite_new_utterance+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for new_utterance in -lflite" >&5 +printf %s "checking for new_utterance in -lflite... " >&6; } +if test ${ac_cv_lib_flite_new_utterance+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lflite $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -5913,57 +6226,55 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char new_utterance (); int -main () +main (void) { return new_utterance (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_flite_new_utterance=yes -else +else $as_nop ac_cv_lib_flite_new_utterance=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_flite_new_utterance" >&5 -$as_echo "$ac_cv_lib_flite_new_utterance" >&6; } -if test "x$ac_cv_lib_flite_new_utterance" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_flite_new_utterance" >&5 +printf "%s\n" "$ac_cv_lib_flite_new_utterance" >&6; } +if test "x$ac_cv_lib_flite_new_utterance" = xyes +then : have_speech=yes -else +else $as_nop have_speech=no fi -for ac_header in flite/flite.h + for ac_header in flite/flite.h do : - ac_fn_c_check_header_mongrel "$LINENO" "flite/flite.h" "ac_cv_header_flite_flite_h" "$ac_includes_default" -if test "x$ac_cv_header_flite_flite_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_FLITE_FLITE_H 1 -_ACEOF + ac_fn_c_check_header_compile "$LINENO" "flite/flite.h" "ac_cv_header_flite_flite_h" "$ac_includes_default" +if test "x$ac_cv_header_flite_flite_h" = xyes +then : + printf "%s\n" "#define HAVE_FLITE_FLITE_H 1" >>confdefs.h have_flite=yes -else +else $as_nop have_flite=no fi done - if test $have_flite = yes -a $have_speech = yes -a $enable_speech = yes; then BUILD_SPEECH="speech say" FLITE_BASE_LIBS="-lflite_usenglish -lflite_cmulex -lflite" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for register_cmu_us_kal16 in -lflite_cmu_us_kal16" >&5 -$as_echo_n "checking for register_cmu_us_kal16 in -lflite_cmu_us_kal16... " >&6; } -if ${ac_cv_lib_flite_cmu_us_kal16_register_cmu_us_kal16+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for register_cmu_us_kal16 in -lflite_cmu_us_kal16" >&5 +printf %s "checking for register_cmu_us_kal16 in -lflite_cmu_us_kal16... " >&6; } +if test ${ac_cv_lib_flite_cmu_us_kal16_register_cmu_us_kal16+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lflite_cmu_us_kal16 $FLITE_BASE_LIBS $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -5972,32 +6283,31 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char register_cmu_us_kal16 (); int -main () +main (void) { return register_cmu_us_kal16 (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_flite_cmu_us_kal16_register_cmu_us_kal16=yes -else +else $as_nop ac_cv_lib_flite_cmu_us_kal16_register_cmu_us_kal16=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_flite_cmu_us_kal16_register_cmu_us_kal16" >&5 -$as_echo "$ac_cv_lib_flite_cmu_us_kal16_register_cmu_us_kal16" >&6; } -if test "x$ac_cv_lib_flite_cmu_us_kal16_register_cmu_us_kal16" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_flite_cmu_us_kal16_register_cmu_us_kal16" >&5 +printf "%s\n" "$ac_cv_lib_flite_cmu_us_kal16_register_cmu_us_kal16" >&6; } +if test "x$ac_cv_lib_flite_cmu_us_kal16_register_cmu_us_kal16" = xyes +then : have_kal16=yes -else +else $as_nop have_kal16=no fi @@ -6011,20 +6321,22 @@ fi # NSSpeechRecognizer #-------------------------------------------------------------------- # Check whether --enable-speech-recognizer was given. -if test "${enable_speech_recognizer+set}" = set; then : +if test ${enable_speech_recognizer+y} +then : enableval=$enable_speech_recognizer; -else +else $as_nop enable_speech_recognizer=yes fi BUILD_SPEECH_RECOGNIZER= # has pocketsphinx, for speech recognition. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ps_start_utt in -lpocketsphinx" >&5 -$as_echo_n "checking for ps_start_utt in -lpocketsphinx... " >&6; } -if ${ac_cv_lib_pocketsphinx_ps_start_utt+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ps_start_utt in -lpocketsphinx" >&5 +printf %s "checking for ps_start_utt in -lpocketsphinx... " >&6; } +if test ${ac_cv_lib_pocketsphinx_ps_start_utt+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lpocketsphinx $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -6033,49 +6345,46 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char ps_start_utt (); int -main () +main (void) { return ps_start_utt (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_pocketsphinx_ps_start_utt=yes -else +else $as_nop ac_cv_lib_pocketsphinx_ps_start_utt=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pocketsphinx_ps_start_utt" >&5 -$as_echo "$ac_cv_lib_pocketsphinx_ps_start_utt" >&6; } -if test "x$ac_cv_lib_pocketsphinx_ps_start_utt" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pocketsphinx_ps_start_utt" >&5 +printf "%s\n" "$ac_cv_lib_pocketsphinx_ps_start_utt" >&6; } +if test "x$ac_cv_lib_pocketsphinx_ps_start_utt" = xyes +then : have_speech_recognizer=yes -else +else $as_nop have_speech_recognizer=no fi -for ac_header in pocketsphinx/pocketsphinx_export.h + for ac_header in pocketsphinx/pocketsphinx_export.h do : - ac_fn_c_check_header_mongrel "$LINENO" "pocketsphinx/pocketsphinx_export.h" "ac_cv_header_pocketsphinx_pocketsphinx_export_h" "$ac_includes_default" -if test "x$ac_cv_header_pocketsphinx_pocketsphinx_export_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_POCKETSPHINX_POCKETSPHINX_EXPORT_H 1 -_ACEOF + ac_fn_c_check_header_compile "$LINENO" "pocketsphinx/pocketsphinx_export.h" "ac_cv_header_pocketsphinx_pocketsphinx_export_h" "$ac_includes_default" +if test "x$ac_cv_header_pocketsphinx_pocketsphinx_export_h" = xyes +then : + printf "%s\n" "#define HAVE_POCKETSPHINX_POCKETSPHINX_EXPORT_H 1" >>confdefs.h have_pocketsphinx=yes -else +else $as_nop have_pocketsphinx=no fi done - if test $have_pocketsphinx = yes -a $have_speech_recognizer = yes -a $enable_speech_recognizer = yes; then BUILD_SPEECH_RECOGNIZER="speech_recognizer" RECOGNIZER_BASE_LIBS=`pkg-config --libs pocketsphinx sphinxbase` @@ -6087,6 +6396,85 @@ fi +#-------------------------------------------------------------------- +# NSMovie / NSMovieView +#-------------------------------------------------------------------- +# Check whether --enable-movie was given. +if test ${enable_movie+y} +then : + enableval=$enable_movie; +else $as_nop + enable_movie=yes +fi + +BUILD_MOVIE= + +# has pocketsphinx, for speech recognition. +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for avcodec_find_decoder in -lavcodec" >&5 +printf %s "checking for avcodec_find_decoder in -lavcodec... " >&6; } +if test ${ac_cv_lib_avcodec_avcodec_find_decoder+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lavcodec $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char avcodec_find_decoder (); +int +main (void) +{ +return avcodec_find_decoder (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_avcodec_avcodec_find_decoder=yes +else $as_nop + ac_cv_lib_avcodec_avcodec_find_decoder=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_avcodec_avcodec_find_decoder" >&5 +printf "%s\n" "$ac_cv_lib_avcodec_avcodec_find_decoder" >&6; } +if test "x$ac_cv_lib_avcodec_avcodec_find_decoder" = xyes +then : + have_avcodec=yes +else $as_nop + have_avcodec=no +fi + + for ac_header in libavcodec/avcodec.h +do : + ac_fn_c_check_header_compile "$LINENO" "libavcodec/avcodec.h" "ac_cv_header_libavcodec_avcodec_h" "$ac_includes_default" +if test "x$ac_cv_header_libavcodec_avcodec_h" = xyes +then : + printf "%s\n" "#define HAVE_LIBAVCODEC_AVCODEC_H 1" >>confdefs.h + have_codec=yes +else $as_nop + have_codec=no +fi + +done +if test $have_avcodec = yes -a $have_codec = yes -a $enable_movie = yes; then + +printf "%s\n" "#define HAVE_AVCODEC 1" >>confdefs.h + +# AC_DEFINE(HAVE_AVCODEC,1) + MOVIE_BASE_LIBS=`pkg-config --libs libavcodec libavformat libavutil libswscale` + MOVIE_BASE_CFLAGS=`pkg-config --cflags libavcodec libavformat libavutil libswscale` +fi + + + #-------------------------------------------------------------------- # Find CUPS #-------------------------------------------------------------------- @@ -6097,9 +6485,10 @@ GSCUPS_DATADIR= BUILD_GSCUPS=NO # Check whether --enable-cups was given. -if test "${enable_cups+set}" = set; then : +if test ${enable_cups+y} +then : enableval=$enable_cups; -else +else $as_nop enable_cups=yes fi @@ -6108,11 +6497,12 @@ if test $enable_cups = yes; then BUILD_GSCUPS=YES # Extract the first word of "cups-config", so it can be a program name with args. set dummy cups-config; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_have_cups+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_have_cups+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$have_cups"; then ac_cv_prog_have_cups="$have_cups" # Let the user override the test. else @@ -6120,11 +6510,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_have_cups="yes" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -6136,11 +6530,11 @@ fi fi have_cups=$ac_cv_prog_have_cups if test -n "$have_cups"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_cups" >&5 -$as_echo "$have_cups" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $have_cups" >&5 +printf "%s\n" "$have_cups" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -6160,30 +6554,29 @@ fi CPPFLAGS="$GSCUPS_CFLAGS ${CPPFLAGS}" LDFLAGS="$GSCUPS_LDFLAGS ${LDFLAGS}" - for ac_header in cups/cups.h + for ac_header in cups/cups.h do : - ac_fn_c_check_header_mongrel "$LINENO" "cups/cups.h" "ac_cv_header_cups_cups_h" "$ac_includes_default" -if test "x$ac_cv_header_cups_cups_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_CUPS_CUPS_H 1 -_ACEOF + ac_fn_c_check_header_compile "$LINENO" "cups/cups.h" "ac_cv_header_cups_cups_h" "$ac_includes_default" +if test "x$ac_cv_header_cups_cups_h" = xyes +then : + printf "%s\n" "#define HAVE_CUPS_CUPS_H 1" >>confdefs.h have_cups=yes -else +else $as_nop have_cups=no fi done - if test "$have_cups" = no; then enable_cups=no BUILD_GSCUPS=NO echo "Could not find cups.h, cups printing support will not be built." fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cupsServer in -lcups" >&5 -$as_echo_n "checking for cupsServer in -lcups... " >&6; } -if ${ac_cv_lib_cups_cupsServer+:} false; then : - $as_echo_n "(cached) " >&6 -else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for cupsServer in -lcups" >&5 +printf %s "checking for cupsServer in -lcups... " >&6; } +if test ${ac_cv_lib_cups_cupsServer+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lcups $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -6192,32 +6585,31 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif char cupsServer (); int -main () +main (void) { return cupsServer (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_cups_cupsServer=yes -else +else $as_nop ac_cv_lib_cups_cupsServer=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cups_cupsServer" >&5 -$as_echo "$ac_cv_lib_cups_cupsServer" >&6; } -if test "x$ac_cv_lib_cups_cupsServer" = xyes; then : +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cups_cupsServer" >&5 +printf "%s\n" "$ac_cv_lib_cups_cupsServer" >&6; } +if test "x$ac_cv_lib_cups_cupsServer" = xyes +then : have_cups=yes -else +else $as_nop have_cups=no fi @@ -6239,8 +6631,8 @@ fi #-------------------------------------------------------------------- # Check for -Wdeclaration-after-statement #-------------------------------------------------------------------- -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wdeclaration-after-statement" >&5 -$as_echo_n "checking whether the compiler supports -Wdeclaration-after-statement... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wdeclaration-after-statement" >&5 +printf %s "checking whether the compiler supports -Wdeclaration-after-statement... " >&6; } saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wdeclaration-after-statement" @@ -6248,23 +6640,24 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : HAS_W_DECL_AFTER_STATEMENT=yes -else +else $as_nop HAS_W_DECL_AFTER_STATEMENT=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS="$saved_CFLAGS" -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAS_W_DECL_AFTER_STATEMENT" >&5 -$as_echo "$HAS_W_DECL_AFTER_STATEMENT" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $HAS_W_DECL_AFTER_STATEMENT" >&5 +printf "%s\n" "$HAS_W_DECL_AFTER_STATEMENT" >&6; } if test x"$HAS_W_DECL_AFTER_STATEMENT" = x"yes"; then WARN_FLAGS="-Wall -Wdeclaration-after-statement" @@ -6285,13 +6678,13 @@ GUILIBS=`gnustep-config --gui-libs` #-------------------------------------------------------------------- # Record the version #-------------------------------------------------------------------- -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the version of gnustep-gui we are compiling" >&5 -$as_echo_n "checking for the version of gnustep-gui we are compiling... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the version of gnustep-gui we are compiling" >&5 +printf %s "checking for the version of gnustep-gui we are compiling... " >&6; } if test -f "Version"; then . ./Version fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $GNUSTEP_GUI_VERSION" >&5 -$as_echo "$GNUSTEP_GUI_VERSION" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GNUSTEP_GUI_VERSION" >&5 +printf "%s\n" "$GNUSTEP_GUI_VERSION" >&6; } @@ -6338,8 +6731,8 @@ _ACEOF case $ac_val in #( *${as_nl}*) case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( @@ -6369,15 +6762,15 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; /^ac_cv_env_/b end t clear :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -$as_echo "$as_me: updating cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +printf "%s\n" "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else @@ -6391,8 +6784,8 @@ $as_echo "$as_me: updating cache $cache_file" >&6;} fi fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache @@ -6409,7 +6802,7 @@ U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" @@ -6425,8 +6818,8 @@ LTLIBOBJS=$ac_ltlibobjs ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL @@ -6449,14 +6842,16 @@ cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : +as_nop=: +if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else +else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( @@ -6466,46 +6861,46 @@ esac fi + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then +if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || @@ -6514,13 +6909,6 @@ if test "${PATH_SEPARATOR+set}" != set; then fi -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( @@ -6529,8 +6917,12 @@ case $0 in #(( for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS @@ -6542,30 +6934,10 @@ if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] @@ -6578,13 +6950,14 @@ as_fn_error () as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - $as_echo "$as_me: error: $2" >&2 + printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error + # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. @@ -6611,18 +6984,20 @@ as_fn_unset () { eval $1=; unset $1;} } as_unset=as_fn_unset + # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null +then : eval 'as_fn_append () { eval $1+=\$2 }' -else +else $as_nop as_fn_append () { eval $1=\$$1\$2 @@ -6634,12 +7009,13 @@ fi # as_fn_append # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : eval 'as_fn_arith () { as_val=$(( $* )) }' -else +else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` @@ -6670,7 +7046,7 @@ as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | +printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q @@ -6692,6 +7068,10 @@ as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) @@ -6705,6 +7085,12 @@ case `echo -n x` in #((((( ECHO_N='-n';; esac +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -6746,7 +7132,7 @@ as_fn_mkdir_p () as_dirs= while :; do case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" @@ -6755,7 +7141,7 @@ $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | +printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -6818,7 +7204,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # values after options handling. ac_log=" This file was extended by $as_me, which was -generated by GNU Autoconf 2.69. Invocation command line was +generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -6876,14 +7262,16 @@ $config_headers Report bugs to the package provider." _ACEOF +ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` +ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ config.status -configured by $0, generated by GNU Autoconf 2.69, +configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" -Copyright (C) 2012 Free Software Foundation, Inc. +Copyright (C) 2021 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -6920,15 +7308,15 @@ do -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - $as_echo "$ac_cs_version"; exit ;; + printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) - $as_echo "$ac_cs_config"; exit ;; + printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" @@ -6936,7 +7324,7 @@ do --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; @@ -6945,7 +7333,7 @@ do as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) - $as_echo "$ac_cs_usage"; exit ;; + printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; @@ -6973,7 +7361,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift - \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" @@ -6987,7 +7375,7 @@ exec 5>>config.log sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX - $as_echo "$ac_log" + printf "%s\n" "$ac_log" } >&5 _ACEOF @@ -7016,8 +7404,8 @@ done # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then - test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files - test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files + test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree @@ -7353,7 +7741,7 @@ do esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac - case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done @@ -7361,17 +7749,17 @@ do # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` - $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" - { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -$as_echo "$as_me: creating $ac_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) - ac_sed_conf_input=`$as_echo "$configure_input" | + ac_sed_conf_input=`printf "%s\n" "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac @@ -7388,7 +7776,7 @@ $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$ac_file" | +printf "%s\n" X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -7412,9 +7800,9 @@ $as_echo X"$ac_file" | case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; @@ -7467,8 +7855,8 @@ ac_sed_dataroot=' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' @@ -7510,9 +7898,9 @@ test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 -$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" @@ -7528,20 +7916,20 @@ which seems to be undefined. Please make sure it is defined" >&2;} # if test x"$ac_file" != x-; then { - $as_echo "/* $configure_input */" \ + printf "%s\n" "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then - { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 -$as_echo "$as_me: $ac_file is unchanged" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +printf "%s\n" "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else - $as_echo "/* $configure_input */" \ + printf "%s\n" "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi @@ -7582,7 +7970,8 @@ if test "$no_create" != yes; then $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi + diff --git a/configure.ac b/configure.ac index 98640cb6b6..cf40bf2367 100644 --- a/configure.ac +++ b/configure.ac @@ -589,6 +589,26 @@ AC_SUBST(RECOGNIZER_BASE_LIBS) AC_SUBST(RECOGNIZER_BASE_CFLAGS) AC_SUBST(RECOGNIZER_ENGINE_CLASS) +#-------------------------------------------------------------------- +# NSMovie / NSMovieView +#-------------------------------------------------------------------- +AC_ARG_ENABLE(movie, + [ --disable-movie Disable NSMovie/NSMovieView functionality],, + enable_movie=yes) +BUILD_MOVIE= + +# has pocketsphinx, for speech recognition. +AC_CHECK_LIB(avcodec, avcodec_find_decoder, have_avcodec=yes, have_avcodec=no) +AC_CHECK_HEADERS(libavcodec/avcodec.h, have_codec=yes, have_codec=no) +if test $have_avcodec = yes -a $have_codec = yes -a $enable_movie = yes; then + AC_DEFINE(HAVE_AVCODEC,1,[Define if you have avcodec for NSMovie]) +# AC_DEFINE(HAVE_AVCODEC,1) + MOVIE_BASE_LIBS=`pkg-config --libs libavcodec libavformat libavutil libswscale` + MOVIE_BASE_CFLAGS=`pkg-config --cflags libavcodec libavformat libavutil libswscale` +fi +AC_SUBST(MOVIE_BASE_LIBS) +AC_SUBST(MOVIE_BASE_CFLAGS) + #-------------------------------------------------------------------- # Find CUPS #-------------------------------------------------------------------- From 472550e1b77e370d846e42e0515578a02e8d20a2 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 26 May 2025 00:14:29 -0400 Subject: [PATCH 03/86] Add new subclass to encapsulate the libav code --- Headers/AppKit/NSMovieView.h | 51 ++++---------- Source/GNUmakefile | 1 + Source/NSMovieView.m | 133 ++--------------------------------- 3 files changed, 19 insertions(+), 166 deletions(-) diff --git a/Headers/AppKit/NSMovieView.h b/Headers/AppKit/NSMovieView.h index 1c9a90e94c..0cdaca3409 100644 --- a/Headers/AppKit/NSMovieView.h +++ b/Headers/AppKit/NSMovieView.h @@ -28,19 +28,10 @@ #ifndef _GNUstep_H_NSMovieView #define _GNUstep_H_NSMovieView -#import +#import #import -#import "config.h" - -#ifdef HAVE_AVCODEC -#include -#include -#include -#include -#endif - @class NSMovie; typedef enum { @@ -52,33 +43,19 @@ typedef enum { APPKIT_EXPORT_CLASS @interface NSMovieView : NSView { - @protected - NSMovie* _movie; - float _rate; - float _volume; - struct NSMovieViewFlags { - unsigned int muted: 1; - unsigned int loopMode: 3; - unsigned int plays_selection_only: 1; - unsigned int plays_every_frame: 1; - unsigned int is_controller_visible: 1; - unsigned int editable: 1; - unsigned int reserved: 24; - } _flags; - BOOL _playing; - NSTimer *_decodeTimer; - - // libav specific... - NSImage *_currentFrame; -#ifdef HAVE_AVCODEC - AVFormatContext *_formatContext; - AVCodecContext *_codecContext; - AVFrame *_avframe; - AVFrame *_avframeRGB; - struct SwsContext *_swsCtx; -#endif - int _videoStreamIndex; - uint8_t *_buffer; + NSMovie* _movie; + float _rate; + float _volume; + BOOL _playing; + struct NSMovieViewFlags { + unsigned int muted: 1; + unsigned int loopMode: 3; + unsigned int plays_selection_only: 1; + unsigned int plays_every_frame: 1; + unsigned int is_controller_visible: 1; + unsigned int editable: 1; + unsigned int reserved: 24; + } _flags; } - (void) setMovie: (NSMovie*)movie; diff --git a/Source/GNUmakefile b/Source/GNUmakefile index 51fb140bb8..62439f8a57 100644 --- a/Source/GNUmakefile +++ b/Source/GNUmakefile @@ -331,6 +331,7 @@ GSHorizontalTypesetter.m \ GSGormLoading.m \ GSIconManager.m \ GSImageMagickImageRep.m \ +GSMovieView.m \ GSNibLoading.m \ GSTheme.m \ GSThemeDrawing.m \ diff --git a/Source/NSMovieView.m b/Source/NSMovieView.m index 6d97c754ed..b7c1ac0cd8 100644 --- a/Source/NSMovieView.m +++ b/Source/NSMovieView.m @@ -39,119 +39,18 @@ #import "AppKit/NSMovieView.h" #import "AppKit/NSPasteboard.h" -#import "config.h" +#import "GSMovieView.h" @implementation NSMovieView -// private method to display frames... -- (void) _updateImage: (NSImage *)image -{ - _currentFrame = image; - [self setNeedsDisplay:YES]; -} - -- (void) _prepareDecoder -{ -#ifdef HAVE_AVCODEC - NSString *moviePath = [[_movie URL] path]; - - _formatContext = avformat_alloc_context(); - if (avformat_open_input(&_formatContext, [moviePath UTF8String], NULL, NULL) != 0) return; - if (avformat_find_stream_info(_formatContext, NULL) < 0) return; - - _videoStreamIndex = -1; - for (int i = 0; i < _formatContext->nb_streams; i++) - { - if (_formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) - { - _videoStreamIndex = i; - break; - } - } - - if (_videoStreamIndex == -1) return; - - AVCodecParameters *codecPar = _formatContext->streams[_videoStreamIndex]->codecpar; - const AVCodec *codec = avcodec_find_decoder(codecPar->codec_id); - - _codecContext = avcodec_alloc_context3(codec); - avcodec_parameters_to_context(_codecContext, codecPar); - if (avcodec_open2(_codecContext, codec, NULL) < 0) return; - - _avframe = av_frame_alloc(); - _avframeRGB = av_frame_alloc(); - - int numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, _codecContext->width, _codecContext->height, 1); - _buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t)); - av_image_fill_arrays(_avframeRGB->data, _avframeRGB->linesize, _buffer, AV_PIX_FMT_RGB24, - _codecContext->width, _codecContext->height, 1); - - _swsCtx = sws_getContext(_codecContext->width, _codecContext->height, _codecContext->pix_fmt, - _codecContext->width, _codecContext->height, AV_PIX_FMT_RGB24, - SWS_BILINEAR, NULL, NULL, NULL); -#endif -} - -- (void) _decodeAndDisplayNextFrame -{ -#ifdef HAVE_AVCODEC - AVPacket packet; - - av_init_packet(&packet); - packet.data = NULL; - packet.size = 0; - - while (av_read_frame(_formatContext, &packet) >= 0) - { - if (!_playing) break; - - if (packet.stream_index == _videoStreamIndex) - { - avcodec_send_packet(_codecContext, &packet); - if (avcodec_receive_frame(_codecContext, _avframe) == 0) - { - sws_scale(_swsCtx, (const uint8_t * const *)_avframe->data, _avframe->linesize, 0, - _codecContext->height, _avframeRGB->data, _avframeRGB->linesize); - - NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] - initWithBitmapDataPlanes: _avframeRGB->data - pixelsWide: _codecContext->width - pixelsHigh: _codecContext->height - bitsPerSample: 8 - samplesPerPixel: 3 - hasAlpha: NO - isPlanar: NO - colorSpaceName: NSCalibratedRGBColorSpace - bytesPerRow: _avframeRGB->linesize[0] - bitsPerPixel: 24]; - - NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize(_codecContext->width, _codecContext->height)]; - [image addRepresentation:rep]; - - [self performSelectorOnMainThread: @selector(_updateImage:) - withObject: image - waitUntilDone: NO]; - break; - } - } - av_packet_unref(&packet); - } -#endif -} - -- (void) drawRect: (NSRect)dirtyRect -{ - [super drawRect: dirtyRect]; - if (_currentFrame) - { - [_currentFrame drawInRect: [self bounds]]; - } +- (id) initWithFrame: (NSRect)frame +{ + return [[GSMovieView alloc] initWithFrame: frame]; } - (void) setMovie: (NSMovie*)movie { ASSIGN(_movie, movie); - [self _prepareDecoder]; } - (NSMovie*) movie @@ -162,35 +61,11 @@ - (NSMovie*) movie - (void) start: (id)sender { _playing = YES; - _rate = 1.0 / 30.0; - _volume = 1.0; - - _decodeTimer = - [NSTimer scheduledTimerWithTimeInterval: _rate - target: self - selector: @selector(decodeAndDisplayNextFrame) - userInfo: nil - repeats: YES]; } - (void) stop: (id)sender { _playing = NO; - - if (_decodeTimer) - { - [_decodeTimer invalidate]; - _decodeTimer = nil; - } - -#ifdef HAVE_AVCODEC - if (_avframe) av_frame_free(&_avframe); - if (_avframeRGB) av_frame_free(&_avframeRGB); - if (_buffer) av_free(_buffer); - if (_codecContext) avcodec_free_context(&_codecContext); - if (_formatContext) avformat_close_input(&_formatContext); - if (_swsCtx) sws_freeContext(_swsCtx); -#endif } - (BOOL) isPlaying From dd2ab8fd06f604655ee42d1e65c3da87f359b924 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 26 May 2025 00:47:33 -0400 Subject: [PATCH 04/86] Update configure, GNUmakefile, NSMovieView --- Source/GNUmakefile | 5 ++++- Source/NSMovieView.m | 6 ++++++ configure | 6 ++++-- configure.ac | 5 +++-- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/Source/GNUmakefile b/Source/GNUmakefile index 62439f8a57..f6ea402528 100644 --- a/Source/GNUmakefile +++ b/Source/GNUmakefile @@ -331,7 +331,6 @@ GSHorizontalTypesetter.m \ GSGormLoading.m \ GSIconManager.m \ GSImageMagickImageRep.m \ -GSMovieView.m \ GSNibLoading.m \ GSTheme.m \ GSThemeDrawing.m \ @@ -377,6 +376,10 @@ GSCSEditVariableManager.m \ GSCSTableau.m \ GSColorSliderCell.m +ifeq ($(BUILD_MOVIE), yes) +libgnustep-gui_OBJC_FILES += GSMovieView.m +endif + # Turn off NSMenuItem warning that NSMenuItem conforms to , # but does not implement 's methods itself (it inherits # their implementation) diff --git a/Source/NSMovieView.m b/Source/NSMovieView.m index b7c1ac0cd8..436d3ad759 100644 --- a/Source/NSMovieView.m +++ b/Source/NSMovieView.m @@ -39,13 +39,19 @@ #import "AppKit/NSMovieView.h" #import "AppKit/NSPasteboard.h" +#ifdef HAVE_AVCODEC #import "GSMovieView.h" +#endif @implementation NSMovieView - (id) initWithFrame: (NSRect)frame { +#ifdef HAVE_AVCODEC return [[GSMovieView alloc] initWithFrame: frame]; +#else + return nil; +#endif } - (void) setMovie: (NSMovie*)movie diff --git a/configure b/configure index 7572cb0508..a3cc348587 100755 --- a/configure +++ b/configure @@ -663,6 +663,7 @@ GSCUPS_LIBS GSCUPS_LDFLAGS GSCUPS_CFLAGS have_cups +BUILD_MOVIE MOVIE_BASE_CFLAGS MOVIE_BASE_LIBS RECOGNIZER_ENGINE_CLASS @@ -6409,7 +6410,7 @@ fi BUILD_MOVIE= -# has pocketsphinx, for speech recognition. +# has avcodec { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for avcodec_find_decoder in -lavcodec" >&5 printf %s "checking for avcodec_find_decoder in -lavcodec... " >&6; } if test ${ac_cv_lib_avcodec_avcodec_find_decoder+y} @@ -6468,13 +6469,14 @@ if test $have_avcodec = yes -a $have_codec = yes -a $enable_movie = yes; then printf "%s\n" "#define HAVE_AVCODEC 1" >>confdefs.h -# AC_DEFINE(HAVE_AVCODEC,1) + BUILD_MOVIE="yes" MOVIE_BASE_LIBS=`pkg-config --libs libavcodec libavformat libavutil libswscale` MOVIE_BASE_CFLAGS=`pkg-config --cflags libavcodec libavformat libavutil libswscale` fi + #-------------------------------------------------------------------- # Find CUPS #-------------------------------------------------------------------- diff --git a/configure.ac b/configure.ac index cf40bf2367..410e8c5f90 100644 --- a/configure.ac +++ b/configure.ac @@ -597,17 +597,18 @@ AC_ARG_ENABLE(movie, enable_movie=yes) BUILD_MOVIE= -# has pocketsphinx, for speech recognition. +# has avcodec AC_CHECK_LIB(avcodec, avcodec_find_decoder, have_avcodec=yes, have_avcodec=no) AC_CHECK_HEADERS(libavcodec/avcodec.h, have_codec=yes, have_codec=no) if test $have_avcodec = yes -a $have_codec = yes -a $enable_movie = yes; then AC_DEFINE(HAVE_AVCODEC,1,[Define if you have avcodec for NSMovie]) -# AC_DEFINE(HAVE_AVCODEC,1) + BUILD_MOVIE="yes" MOVIE_BASE_LIBS=`pkg-config --libs libavcodec libavformat libavutil libswscale` MOVIE_BASE_CFLAGS=`pkg-config --cflags libavcodec libavformat libavutil libswscale` fi AC_SUBST(MOVIE_BASE_LIBS) AC_SUBST(MOVIE_BASE_CFLAGS) +AC_SUBST(BUILD_MOVIE) #-------------------------------------------------------------------- # Find CUPS From 0b28f09679549b76df5c20a7393acc854f0ca31d Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 26 May 2025 00:47:52 -0400 Subject: [PATCH 05/86] Add subclass --- Source/GSMovieView.h | 66 ++++++++++++++ Source/GSMovieView.m | 209 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 275 insertions(+) create mode 100644 Source/GSMovieView.h create mode 100644 Source/GSMovieView.m diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h new file mode 100644 index 0000000000..411f5555bc --- /dev/null +++ b/Source/GSMovieView.h @@ -0,0 +1,66 @@ +/** NSMovieView + + Encapsulate a view for Quicktime movies + + Copyright (C) 2003 Free Software Foundation, Inc. + + Author: Fred Kiefer + Date: March 2003 + + This file is part of the GNUstep GUI Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; see the file COPYING.LIB. + If not, see or write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _GNUstep_H_GSMovieView +#define _GNUstep_H_GSMovieView + +#import "config.h" + +#import "AppKit/NSMovieView.h" + +#include +#include +#include +#include + +@class NSImage; +@class NSTimer; + +APPKIT_EXPORT_CLASS +@interface GSMovieView : NSMovieView +{ + NSImage *_currentFrame; +#ifdef HAVE_AVCODEC + AVFormatContext *_formatContext; + AVCodecContext *_codecContext; + AVFrame *_avframe; + AVFrame *_avframeRGB; + struct SwsContext *_swsCtx; +#endif + int _videoStreamIndex; + uint8_t *_buffer; + NSTimer *_decodeTimer; +} + +- (void) updateImage: (NSImage *)image; +- (void) prepareDecoder; +- (void) decodeAndDisplayNextFrame; + +@end + +#endif /* _GNUstep_H_NSMovieView */ diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m new file mode 100644 index 0000000000..2698be42ee --- /dev/null +++ b/Source/GSMovieView.m @@ -0,0 +1,209 @@ +/** GSMovieView + + Encapsulate a movie + + Copyright (C) 2025 Free Software Foundation, Inc. + + Author: Gregory Casamento + Date: May 2025 + + This file is part of the GNUstep GUI Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; see the file COPYING.LIB. + If not, see or write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#import "config.h" + +#import +#import +#import +#import + +#import "AppKit/NSColor.h" +#import "AppKit/NSGraphics.h" +#import "AppKit/NSImage.h" +#import "AppKit/NSImageRep.h" +#import "AppKit/NSMovie.h" +#import "AppKit/NSPasteboard.h" + +#import "GSMovieView.h" + +@implementation GSMovieView + +// private method to display frames... +- (void) updateImage: (NSImage *)image +{ + _currentFrame = image; + [self setNeedsDisplay:YES]; +} + +- (void) prepareDecoder +{ + NSString *moviePath = [[_movie URL] path]; + + _formatContext = avformat_alloc_context(); + if (avformat_open_input(&_formatContext, [moviePath UTF8String], NULL, NULL) != 0) return; + if (avformat_find_stream_info(_formatContext, NULL) < 0) return; + + _videoStreamIndex = -1; + for (int i = 0; i < _formatContext->nb_streams; i++) + { + if (_formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) + { + _videoStreamIndex = i; + break; + } + } + + if (_videoStreamIndex == -1) return; + + AVCodecParameters *codecPar = _formatContext->streams[_videoStreamIndex]->codecpar; + const AVCodec *codec = avcodec_find_decoder(codecPar->codec_id); + + _codecContext = avcodec_alloc_context3(codec); + avcodec_parameters_to_context(_codecContext, codecPar); + if (avcodec_open2(_codecContext, codec, NULL) < 0) return; + + _avframe = av_frame_alloc(); + _avframeRGB = av_frame_alloc(); + + int numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, _codecContext->width, _codecContext->height, 1); + _buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t)); + av_image_fill_arrays(_avframeRGB->data, _avframeRGB->linesize, _buffer, AV_PIX_FMT_RGB24, + _codecContext->width, _codecContext->height, 1); + + _swsCtx = sws_getContext(_codecContext->width, _codecContext->height, _codecContext->pix_fmt, + _codecContext->width, _codecContext->height, AV_PIX_FMT_RGB24, + SWS_BILINEAR, NULL, NULL, NULL); +} + +- (void) decodeAndDisplayNextFrame +{ + AVPacket packet; + + av_init_packet(&packet); + packet.data = NULL; + packet.size = 0; + + while (av_read_frame(_formatContext, &packet) >= 0) + { + if (!_playing) break; + + if (packet.stream_index == _videoStreamIndex) + { + avcodec_send_packet(_codecContext, &packet); + if (avcodec_receive_frame(_codecContext, _avframe) == 0) + { + sws_scale(_swsCtx, (const uint8_t * const *)_avframe->data, _avframe->linesize, 0, + _codecContext->height, _avframeRGB->data, _avframeRGB->linesize); + + NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] + initWithBitmapDataPlanes: _avframeRGB->data + pixelsWide: _codecContext->width + pixelsHigh: _codecContext->height + bitsPerSample: 8 + samplesPerPixel: 3 + hasAlpha: NO + isPlanar: NO + colorSpaceName: NSCalibratedRGBColorSpace + bytesPerRow: _avframeRGB->linesize[0] + bitsPerPixel: 24]; + + NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize(_codecContext->width, _codecContext->height)]; + [image addRepresentation:rep]; + + [self performSelectorOnMainThread: @selector(_updateImage:) + withObject: image + waitUntilDone: NO]; + break; + } + } + av_packet_unref(&packet); + } +} + +- (void) drawRect: (NSRect)dirtyRect +{ + [super drawRect: dirtyRect]; + if (_currentFrame) + { + [_currentFrame drawInRect: [self bounds]]; + } +} + +- (void) setMovie: (NSMovie*)movie +{ + [super setMovie: movie]; + [self prepareDecoder]; +} + +- (void) start: (id)sender +{ + [super start: sender]; + [self setRate: 1.0 / 30.0]; + [self setVolume: 1.0]; + + _decodeTimer = + [NSTimer scheduledTimerWithTimeInterval: [self rate] + target: self + selector: @selector(decodeAndDisplayNextFrame) + userInfo: nil + repeats: YES]; +} + +- (void) stop: (id)sender +{ + [super stop: sender]; + + if (_decodeTimer) + { + [_decodeTimer invalidate]; + _decodeTimer = nil; + } + + if (_avframe) + { + av_frame_free(&_avframe); + } + + if (_avframeRGB) + { + av_frame_free(&_avframeRGB); + } + + if (_buffer) + { + av_free(_buffer); + } + + if (_codecContext) + { + avcodec_free_context(&_codecContext); + } + + if (_formatContext) + { + avformat_close_input(&_formatContext); + } + + if (_swsCtx) + { + sws_freeContext(_swsCtx); + } +} + +@end From 0191af1cb0eb54de2ff00d2a0be38bcb768d520e Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 26 May 2025 11:34:52 -0400 Subject: [PATCH 06/86] Update NSMovieView to instantiate GSMovieView subclass --- Source/GSMovieView.m | 2 +- Source/NSMovieView.m | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 2698be42ee..b12917433d 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -126,7 +126,7 @@ - (void) decodeAndDisplayNextFrame NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize(_codecContext->width, _codecContext->height)]; [image addRepresentation:rep]; - [self performSelectorOnMainThread: @selector(_updateImage:) + [self performSelectorOnMainThread: @selector(updateImage:) withObject: image waitUntilDone: NO]; break; diff --git a/Source/NSMovieView.m b/Source/NSMovieView.m index 436d3ad759..37750fb587 100644 --- a/Source/NSMovieView.m +++ b/Source/NSMovieView.m @@ -26,6 +26,8 @@ Boston, MA 02110-1301, USA. */ +#import "config.h" + #import #import #import @@ -45,14 +47,16 @@ @implementation NSMovieView -- (id) initWithFrame: (NSRect)frame -{ #ifdef HAVE_AVCODEC - return [[GSMovieView alloc] initWithFrame: frame]; -#else - return nil; -#endif ++ (id) allocWithZone: (NSZone *)zone +{ + if (self == [NSMovieView class]) + { + return [GSMovieView allocWithZone: zone]; + } + return [super allocWithZone: zone]; } +#endif - (void) setMovie: (NSMovie*)movie { From 65f6ef3e6e74679e6cea35ee47dd51ae128e7477 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 26 May 2025 12:52:00 -0400 Subject: [PATCH 07/86] Update memory management in the GSMovieView/NSMovieView classes --- Source/GSMovieView.m | 52 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index b12917433d..c0cfb4bc49 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -44,10 +44,41 @@ @implementation GSMovieView -// private method to display frames... +- (instancetype) initWithFrame: (NSRect)frame +{ + self = [super initWithFrame: frame]; + if (self != nil) + { + _videoStreamIndex = -1; + _decodeTimer = nil; + _currentFrame = nil; + _buffer = NULL; + _swsCtx = NULL; + _avframe = NULL; + _avframeRGB = NULL; + _codecContext = NULL; + _formatContext = NULL; + } + return self; +} + +- (void) dealloc +{ + [self stop: nil]; + RELEASE(_currentFrame); + [super dealloc]; +} + +- (void) resetDecoder +{ + [self stop: nil]; + RELEASE(_currentFrame); + _videoStreamIndex = -1; +} + - (void) updateImage: (NSImage *)image { - _currentFrame = image; + ASSIGN(_currentFrame, image); [self setNeedsDisplay:YES]; } @@ -122,13 +153,16 @@ - (void) decodeAndDisplayNextFrame colorSpaceName: NSCalibratedRGBColorSpace bytesPerRow: _avframeRGB->linesize[0] bitsPerPixel: 24]; - - NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize(_codecContext->width, _codecContext->height)]; + NSSize imageSize = NSMakeSize(_codecContext->width, _codecContext->height); + NSImage *image = [[NSImage alloc] initWithSize: imageSize]; + [image addRepresentation:rep]; - [self performSelectorOnMainThread: @selector(updateImage:) withObject: image waitUntilDone: NO]; + // AUTORELEASE(image); + AUTORELEASE(rep); + break; } } @@ -147,6 +181,7 @@ - (void) drawRect: (NSRect)dirtyRect - (void) setMovie: (NSMovie*)movie { + [self resetDecoder]; [super setMovie: movie]; [self prepareDecoder]; } @@ -172,37 +207,44 @@ - (void) stop: (id)sender if (_decodeTimer) { [_decodeTimer invalidate]; + RELEASE(_decodeTimer); _decodeTimer = nil; } if (_avframe) { av_frame_free(&_avframe); + _avframe = NULL; } if (_avframeRGB) { av_frame_free(&_avframeRGB); + _avframeRGB = NULL; } if (_buffer) { av_free(_buffer); + _buffer = NULL; } if (_codecContext) { avcodec_free_context(&_codecContext); + _codecContext = NULL; } if (_formatContext) { avformat_close_input(&_formatContext); + _formatContext = NULL; } if (_swsCtx) { sws_freeContext(_swsCtx); + _swsCtx = NULL; } } From 924bf25f26031a280c1769251cb4f744c8df83c3 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 26 May 2025 13:15:42 -0400 Subject: [PATCH 08/86] Update comments --- Headers/AppKit/NSMovie.h | 2 ++ Headers/AppKit/NSMovieView.h | 2 ++ Source/GSMovieView.h | 4 ++-- Source/NSMovie.m | 2 ++ Source/NSMovieView.m | 2 ++ 5 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Headers/AppKit/NSMovie.h b/Headers/AppKit/NSMovie.h index c0b9977ba9..69d254ab97 100644 --- a/Headers/AppKit/NSMovie.h +++ b/Headers/AppKit/NSMovie.h @@ -4,6 +4,8 @@ Copyright (C) 2003 Free Software Foundation, Inc. + Author: Gregory John Casamento + Date: May 2025 Author: Fred Kiefer Date: March 2003 diff --git a/Headers/AppKit/NSMovieView.h b/Headers/AppKit/NSMovieView.h index 0cdaca3409..12a9a68b05 100644 --- a/Headers/AppKit/NSMovieView.h +++ b/Headers/AppKit/NSMovieView.h @@ -4,6 +4,8 @@ Copyright (C) 2003 Free Software Foundation, Inc. + Author: Gregory John Casamento + Date: May 2025 Author: Fred Kiefer Date: March 2003 diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index 411f5555bc..a3ea8e9726 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -4,8 +4,8 @@ Copyright (C) 2003 Free Software Foundation, Inc. - Author: Fred Kiefer - Date: March 2003 + Author: Gregory John Casamento + Date: May 2025 This file is part of the GNUstep GUI Library. diff --git a/Source/NSMovie.m b/Source/NSMovie.m index 10127d9466..a563399422 100644 --- a/Source/NSMovie.m +++ b/Source/NSMovie.m @@ -4,6 +4,8 @@ Copyright (C) 2003 Free Software Foundation, Inc. + Author: Gregory John Casamento + Date: May 2025 Author: Fred Kiefer Date: March 2003 diff --git a/Source/NSMovieView.m b/Source/NSMovieView.m index 37750fb587..e51d8bde09 100644 --- a/Source/NSMovieView.m +++ b/Source/NSMovieView.m @@ -4,6 +4,8 @@ Copyright (C) 2003 Free Software Foundation, Inc. + Author: Gregory John Casamento + Date: May 2025 Author: Fred Kiefer Date: March 2003 From 92d678215eaf72d6169623084f73e732706a362d Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 26 May 2025 13:30:35 -0400 Subject: [PATCH 09/86] Update comments --- Headers/AppKit/NSMovie.h | 35 ++++++++++++++++++++++++++++++++--- Source/NSMovie.m | 10 +++++----- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/Headers/AppKit/NSMovie.h b/Headers/AppKit/NSMovie.h index 69d254ab97..f3df3a489d 100644 --- a/Headers/AppKit/NSMovie.h +++ b/Headers/AppKit/NSMovie.h @@ -48,15 +48,44 @@ APPKIT_EXPORT_CLASS BOOL _tmp; } +/** + * An array of all of the types NSMovie can support. + */ + (NSArray*) movieUnfilteredFileTypes; + +/** + * An array of all of the pasteboard types NSMovie can support. + */ + (NSArray*) movieUnfilteredPasteboardTypes; + +/** + * Returns YES, if the object can be initialized with the given pasteboard. + */ + (BOOL) canInitWithPasteboard: (NSPasteboard*)pasteboard; -- (id) initWithMovie: (void*)movie; -- (id) initWithURL: (NSURL*)url byReference: (BOOL)byRef; -- (id) initWithPasteboard: (NSPasteboard*)pasteboard; +/** + * Returns an NSMovie with the raw data pointed to by movie. + */ +- (instancetype) initWithMovie: (void*)movie; + +/** + * Returns an NSMovie with the given URL. byRef should be YES if it is by reference. + */ +- (instancetype) initWithURL: (NSURL*)url byReference: (BOOL)byRef; +/** + * Returns an NSMovie initialized with the pasteboard passed in. + */ +- (instancetype) initWithPasteboard: (NSPasteboard*)pasteboard; + +/** + * Returns the raw data for the movie. + */ - (void*) QTMovie; + +/** + * Returns the URL of the movie to be played. + */ - (NSURL*) URL; @end diff --git a/Source/NSMovie.m b/Source/NSMovie.m index a563399422..d12d342e36 100644 --- a/Source/NSMovie.m +++ b/Source/NSMovie.m @@ -74,7 +74,7 @@ + (BOOL) canInitWithPasteboard: (NSPasteboard*)pasteboard return ([pbTypes firstObjectCommonWithArray: myTypes] != nil); } -- (id) initWithData: (NSData *)movie +- (instancetype) initWithData: (NSData *)movie { if (movie == nil) { @@ -95,12 +95,12 @@ - (id) initWithData: (NSData *)movie return self; } -- (id) initWithMovie: (void*)movie +- (instancetype) initWithMovie: (void*)movie { return [self initWithData: movie]; } -- (id) initWithURL: (NSURL*)url byReference: (BOOL)byRef +- (instancetype) initWithURL: (NSURL*)url byReference: (BOOL)byRef { self = [super init]; if (self != nil) @@ -111,7 +111,7 @@ - (id) initWithURL: (NSURL*)url byReference: (BOOL)byRef return self; } -- (id) initWithPasteboard: (NSPasteboard*)pasteboard +- (instancetype) initWithPasteboard: (NSPasteboard*)pasteboard { NSString *type; NSData* data; @@ -183,7 +183,7 @@ - (void) encodeWithCoder: (NSCoder*)aCoder } } -- (id) initWithCoder: (NSCoder*)aDecoder +- (instancetype) initWithCoder: (NSCoder*)aDecoder { if ([aDecoder allowsKeyedCoding]) { From 5cdb5ff8ac2f5148accb31cd9ce3cafe168cd804 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 26 May 2025 13:39:32 -0400 Subject: [PATCH 10/86] NSMovieView documentation --- Headers/AppKit/NSMovieView.h | 134 +++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) diff --git a/Headers/AppKit/NSMovieView.h b/Headers/AppKit/NSMovieView.h index 12a9a68b05..c61615909a 100644 --- a/Headers/AppKit/NSMovieView.h +++ b/Headers/AppKit/NSMovieView.h @@ -60,50 +60,184 @@ APPKIT_EXPORT_CLASS } _flags; } +/** + * Set the movie to be displayed in the view. + */ - (void) setMovie: (NSMovie*)movie; + +/** + * Get the current movie displayed in the view. + */ - (NSMovie*) movie; +/** + * Start movie playback. + */ - (void) start: (id)sender; + +/** + * Stop movie playback. + */ - (void) stop: (id)sender; + +/** + * Check whether the movie is currently playing. + */ - (BOOL) isPlaying; +/** + * Go to the movie's poster frame. + */ - (void) gotoPosterFrame: (id)sender; + +/** + * Move to the beginning of the movie. + */ - (void) gotoBeginning: (id)sender; + +/** + * Move to the end of the movie. + */ - (void) gotoEnd: (id)sender; + +/** + * Step forward one frame in the movie. + */ - (void) stepForward: (id)sender; + +/** + * Step backward one frame in the movie. + */ - (void) stepBack: (id)sender; +/** + * Set the playback rate for the movie. + */ - (void) setRate: (float)rate; + +/** + * Get the current playback rate. + */ - (float) rate; +/** + * Set the playback volume. + */ - (void) setVolume: (float)volume; + +/** + * Get the current playback volume. + */ - (float) volume; + +/** + * Mute or unmute the playback. + */ - (void) setMuted: (BOOL)mute; + +/** + * Return whether the playback is muted. + */ - (BOOL) isMuted; +/** + * Set the loop mode for playback. + */ - (void) setLoopMode: (NSQTMovieLoopMode)mode; + +/** + * Get the current loop mode. + */ - (NSQTMovieLoopMode) loopMode; + +/** + * Set whether only the selected portion should play. + */ - (void) setPlaysSelectionOnly: (BOOL)flag; + +/** + * Return whether only the selection is played. + */ - (BOOL) playsSelectionOnly; + +/** + * Set whether to play every frame regardless of timing. + */ - (void) setPlaysEveryFrame: (BOOL)flag; + +/** + * Return whether every frame is being played. + */ - (BOOL) playsEveryFrame; +/** + * Show or hide the movie controller and optionally adjust view size. + */ - (void) showController: (BOOL)show adjustingSize: (BOOL)adjustSize; + +/** + * Get a pointer to the movie controller. + */ - (void*) movieController; + +/** + * Check whether the controller is currently visible. + */ - (BOOL) isControllerVisible; +/** + * Get the rectangle in which the movie is displayed. + */ - (NSRect) movieRect; + +/** + * Resize the view based on a magnification factor. + */ - (void) resizeWithMagnification: (float)magnification; + +/** + * Calculate the size of the view at a given magnification. + */ - (NSSize) sizeForMagnification: (float)magnification; +/** + * Set whether the movie view is editable. + */ - (void) setEditable: (BOOL)editable; + +/** + * Return whether the movie view is editable. + */ - (BOOL) isEditable; +/** + * Cut the selected movie content. + */ - (void) cut: (id)sender; + +/** + * Copy the selected movie content. + */ - (void) copy: (id)sender; + +/** + * Paste movie content from the pasteboard. + */ - (void) paste: (id)sender; + +/** + * Clear the selected movie content. + */ - (void) clear: (id)sender; + +/** + * Undo the last operation. + */ - (void) undo: (id)sender; + +/** + * Select all content in the movie view. + */ - (void) selectAll: (id)sender; @end From cb9838b6264575b691a02f448e1d1c858217cd79 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 26 May 2025 15:09:55 -0400 Subject: [PATCH 11/86] Initial changes to get audio working, may not compile --- Source/GSMovieView.h | 1 + Source/GSMovieView.m | 171 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 154 insertions(+), 18 deletions(-) diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index a3ea8e9726..35d89daeb5 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -53,6 +53,7 @@ APPKIT_EXPORT_CLASS struct SwsContext *_swsCtx; #endif int _videoStreamIndex; + int _audioStreamIndex; uint8_t *_buffer; NSTimer *_decodeTimer; } diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index c0cfb4bc49..aece9c33f7 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -21,8 +21,8 @@ You should have received a copy of the GNU Lesser General Public License along with this library; see the file COPYING.LIB. - If not, see or write to the - Free Software Foundation, 51 Franklin Street, Fifth Floor, + If not, see or write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -42,14 +42,121 @@ #import "GSMovieView.h" +@interface FFmpegAudioPlayer : NSObject +{ + AVCodecContext *audioCodecCtx; + AVFrame *audioFrame; + SwrContext *swrCtx; +} + +- (void)prepareAudioWithFormatContext:(AVFormatContext *)formatCtx streamIndex:(int)audioStreamIndex; +- (void)decodeAudioPacket:(AVPacket *)packet; + +@end + +@implementation FFmpegAudioPlayer +- (void)prepareAudioWithFormatContext:(AVFormatContext *)formatCtx streamIndex:(int)audioStreamIndex +{ + AVCodecParameters *audioPar = formatCtx->streams[audioStreamIndex]->codecpar; + AVCodec *audioCodec = avcodec_find_decoder(audioPar->codec_id); + if (!audioCodec) + { + NSLog(@"Audio codec not found."); + return; + } + audioCodecCtx = avcodec_alloc_context3(audioCodec); + avcodec_parameters_to_context(audioCodecCtx, audioPar); + if (avcodec_open2(audioCodecCtx, audioCodec, NULL) < 0) + { + NSLog(@"Failed to open audio codec."); + return; + } + + audioFrame = av_frame_alloc(); + swrCtx = swr_alloc_set_opts(NULL, + AV_CH_LAYOUT_STEREO, + AV_SAMPLE_FMT_S16, + audioCodecCtx->sample_rate, + audioCodecCtx->channel_layout, + audioCodecCtx->sample_fmt, + audioCodecCtx->sample_rate, + 0, NULL); + swr_init(swrCtx); + + NSLog(@"Audio codec: %s, Sample rate: %d, Channels: %d", + audioCodec->name, + audioPar->sample_rate, + audioPar->channels); +} + +- (void)decodeAudioPacket:(AVPacket *)packet +{ + if (!audioCodecCtx || !swrCtx) return; + if (avcodec_send_packet(audioCodecCtx, packet) < 0) return; + while (avcodec_receive_frame(audioCodecCtx, audioFrame) == 0) + { + int outSamples = audioFrame->nb_samples; + int outBytes = av_samples_get_buffer_size(NULL, 2, outSamples, AV_SAMPLE_FMT_S16, 1); + uint8_t *outBuf = (uint8_t *)malloc(outBytes); + uint8_t *outPtrs[] = { outBuf }; + + swr_convert(swrCtx, outPtrs, outSamples, + (const uint8_t **)audioFrame->data, outSamples); + + [audioBuffer appendBytes:outBuf length:outBytes]; + free(outBuf); + } +} + +- (void)finalizeAndPlayBuffer +{ + int sampleRate = audioCodecCtx->sample_rate; + int outBytes = (int)[audioBuffer length]; + int byteRate = sampleRate * 2 * 2; + int blockAlign = 2 * 2; + + NSMutableData *wav = [NSMutableData data]; + [wav appendBytes:"RIFF" length:4]; + uint32_t chunkSize = 36 + outBytes; + [wav appendBytes:&chunkSize length:4]; + [wav appendBytes:"WAVEfmt " length:8]; + + uint32_t subchunk1Size = 16; + [wav appendBytes:&subchunk1Size length:4]; + uint16_t audioFormat = 1, numChannels = 2, bitsPerSample = 16; + [wav appendBytes:&audioFormat length:2]; + [wav appendBytes:&numChannels length:2]; + [wav appendBytes:&sampleRate length:4]; + [wav appendBytes:&byteRate length:4]; + [wav appendBytes:&blockAlign length:2]; + [wav appendBytes:&bitsPerSample length:2]; + + [wav appendBytes:"data" length:4]; + [wav appendBytes:&outBytes length:4]; + [wav appendData:audioBuffer]; + + sound = [[NSSound alloc] initWithData:wav]; + [sound play]; +} + +- (void)dealloc +{ + if (audioFrame) av_frame_free(&audioFrame); + if (audioCodecCtx) avcodec_free_context(&audioCodecCtx); + if (swrCtx) swr_free(&swrCtx); + [super dealloc]; +} +@end + @implementation GSMovieView - (instancetype) initWithFrame: (NSRect)frame { self = [super initWithFrame: frame]; if (self != nil) - { + { _videoStreamIndex = -1; + _audioStreamIndex = -1; _decodeTimer = nil; _currentFrame = nil; _buffer = NULL; @@ -69,11 +176,34 @@ - (void) dealloc [super dealloc]; } +- (void)logStreamMetadata +{ + AVStream *vs = formatContext->streams[videoStreamIndex]; + double duration = (double)formatContext->duration / AV_TIME_BASE; + NSString *info = [NSString stringWithFormat:@"Video: %dx%d %@ %.2fs", + codecContext->width, + codecContext->height, + [NSString stringWithUTF8String:avcodec_get_name(codecContext->codec_id)], + duration]; + [metadataLabel setStringValue:info]; + NSLog(@"%@", info); + + if (audioStreamIndex != -1) + { + AVCodecParameters *ap = formatContext->streams[audioStreamIndex]->codecpar; + NSLog(@"Audio codec: %s, sample rate: %d, channels: %d", + avcodec_get_name(ap->codec_id), + ap->sample_rate, + ap->channels); + } +} + - (void) resetDecoder { [self stop: nil]; RELEASE(_currentFrame); _videoStreamIndex = -1; + _audioStreamIndex = -1; } - (void) updateImage: (NSImage *)image @@ -89,34 +219,39 @@ - (void) prepareDecoder _formatContext = avformat_alloc_context(); if (avformat_open_input(&_formatContext, [moviePath UTF8String], NULL, NULL) != 0) return; if (avformat_find_stream_info(_formatContext, NULL) < 0) return; - + _videoStreamIndex = -1; + _audioStreamIndex = -1; for (int i = 0; i < _formatContext->nb_streams; i++) { - if (_formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) + AVMediaType type = formatContext->streams[i]->codecpar->codec_type; + if (type == AVMEDIA_TYPE_VIDEO && _videoStreamIndex == -1) { _videoStreamIndex = i; - break; + } + else if (type == AVMEDIA_TYPE_AUDIO && _audioStreamIndex == -1) + { + _audioStreamIndex = i; } } - + if (_videoStreamIndex == -1) return; - + AVCodecParameters *codecPar = _formatContext->streams[_videoStreamIndex]->codecpar; const AVCodec *codec = avcodec_find_decoder(codecPar->codec_id); _codecContext = avcodec_alloc_context3(codec); avcodec_parameters_to_context(_codecContext, codecPar); if (avcodec_open2(_codecContext, codec, NULL) < 0) return; - + _avframe = av_frame_alloc(); _avframeRGB = av_frame_alloc(); - + int numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, _codecContext->width, _codecContext->height, 1); _buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t)); av_image_fill_arrays(_avframeRGB->data, _avframeRGB->linesize, _buffer, AV_PIX_FMT_RGB24, _codecContext->width, _codecContext->height, 1); - + _swsCtx = sws_getContext(_codecContext->width, _codecContext->height, _codecContext->pix_fmt, _codecContext->width, _codecContext->height, AV_PIX_FMT_RGB24, SWS_BILINEAR, NULL, NULL, NULL); @@ -129,11 +264,11 @@ - (void) decodeAndDisplayNextFrame av_init_packet(&packet); packet.data = NULL; packet.size = 0; - + while (av_read_frame(_formatContext, &packet) >= 0) { if (!_playing) break; - + if (packet.stream_index == _videoStreamIndex) { avcodec_send_packet(_codecContext, &packet); @@ -141,7 +276,7 @@ - (void) decodeAndDisplayNextFrame { sws_scale(_swsCtx, (const uint8_t * const *)_avframe->data, _avframe->linesize, 0, _codecContext->height, _avframeRGB->data, _avframeRGB->linesize); - + NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: _avframeRGB->data pixelsWide: _codecContext->width @@ -162,7 +297,7 @@ - (void) decodeAndDisplayNextFrame waitUntilDone: NO]; // AUTORELEASE(image); AUTORELEASE(rep); - + break; } } @@ -191,7 +326,7 @@ - (void) start: (id)sender [super start: sender]; [self setRate: 1.0 / 30.0]; [self setVolume: 1.0]; - + _decodeTimer = [NSTimer scheduledTimerWithTimeInterval: [self rate] target: self @@ -210,13 +345,13 @@ - (void) stop: (id)sender RELEASE(_decodeTimer); _decodeTimer = nil; } - + if (_avframe) { av_frame_free(&_avframe); _avframe = NULL; } - + if (_avframeRGB) { av_frame_free(&_avframeRGB); From 8ded62595d8fe8994fcfda6f1fd1c10701c731d9 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 26 May 2025 15:56:34 -0400 Subject: [PATCH 12/86] Add initial changes for sound --- Source/GSMovieView.m | 88 ++++++++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 40 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index aece9c33f7..0e698dd5a9 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -39,14 +39,19 @@ #import "AppKit/NSImageRep.h" #import "AppKit/NSMovie.h" #import "AppKit/NSPasteboard.h" +#import "AppKit/NSSound.h" #import "GSMovieView.h" +#include + @interface FFmpegAudioPlayer : NSObject { - AVCodecContext *audioCodecCtx; - AVFrame *audioFrame; - SwrContext *swrCtx; + AVCodecContext *_audioCodecCtx; + AVFrame *_audioFrame; + SwrContext *_swrCtx; + NSMutableData *_audioBuffer; + NSSound *_sound; } - (void)prepareAudioWithFormatContext:(AVFormatContext *)formatCtx streamIndex:(int)audioStreamIndex; @@ -55,6 +60,7 @@ - (void)decodeAudioPacket:(AVPacket *)packet; @end @implementation FFmpegAudioPlayer + - (void)prepareAudioWithFormatContext:(AVFormatContext *)formatCtx streamIndex:(int)audioStreamIndex { AVCodecParameters *audioPar = formatCtx->streams[audioStreamIndex]->codecpar; @@ -64,24 +70,24 @@ - (void)prepareAudioWithFormatContext:(AVFormatContext *)formatCtx streamIndex:( NSLog(@"Audio codec not found."); return; } - audioCodecCtx = avcodec_alloc_context3(audioCodec); - avcodec_parameters_to_context(audioCodecCtx, audioPar); - if (avcodec_open2(audioCodecCtx, audioCodec, NULL) < 0) + _audioCodecCtx = avcodec_alloc_context3(audioCodec); + avcodec_parameters_to_context(_audioCodecCtx, audioPar); + if (avcodec_open2(_audioCodecCtx, audioCodec, NULL) < 0) { - NSLog(@"Failed to open audio codec."); + NSLog(@"Failed to open _audio codec."); return; } - audioFrame = av_frame_alloc(); - swrCtx = swr_alloc_set_opts(NULL, + _audioFrame = av_frame_alloc(); + _swrCtx = swr_alloc_set_opts(NULL, AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_S16, - audioCodecCtx->sample_rate, - audioCodecCtx->channel_layout, - audioCodecCtx->sample_fmt, - audioCodecCtx->sample_rate, + _audioCodecCtx->sample_rate, + _audioCodecCtx->channel_layout, + _audioCodecCtx->sample_fmt, + _audioCodecCtx->sample_rate, 0, NULL); - swr_init(swrCtx); + swr_init(_swrCtx); NSLog(@"Audio codec: %s, Sample rate: %d, Channels: %d", audioCodec->name, @@ -91,27 +97,27 @@ - (void)prepareAudioWithFormatContext:(AVFormatContext *)formatCtx streamIndex:( - (void)decodeAudioPacket:(AVPacket *)packet { - if (!audioCodecCtx || !swrCtx) return; - if (avcodec_send_packet(audioCodecCtx, packet) < 0) return; - while (avcodec_receive_frame(audioCodecCtx, audioFrame) == 0) + if (!_audioCodecCtx || !_swrCtx) return; + if (avcodec_send_packet(_audioCodecCtx, packet) < 0) return; + while (avcodec_receive_frame(_audioCodecCtx, _audioFrame) == 0) { - int outSamples = audioFrame->nb_samples; + int outSamples = _audioFrame->nb_samples; int outBytes = av_samples_get_buffer_size(NULL, 2, outSamples, AV_SAMPLE_FMT_S16, 1); uint8_t *outBuf = (uint8_t *)malloc(outBytes); uint8_t *outPtrs[] = { outBuf }; - swr_convert(swrCtx, outPtrs, outSamples, - (const uint8_t **)audioFrame->data, outSamples); + swr_convert(_swrCtx, outPtrs, outSamples, + (const uint8_t **)_audioFrame->data, outSamples); - [audioBuffer appendBytes:outBuf length:outBytes]; + [_audioBuffer appendBytes:outBuf length:outBytes]; free(outBuf); } } - (void)finalizeAndPlayBuffer { - int sampleRate = audioCodecCtx->sample_rate; - int outBytes = (int)[audioBuffer length]; + int sampleRate = _audioCodecCtx->sample_rate; + int outBytes = (int)[_audioBuffer length]; int byteRate = sampleRate * 2 * 2; int blockAlign = 2 * 2; @@ -133,19 +139,20 @@ - (void)finalizeAndPlayBuffer [wav appendBytes:"data" length:4]; [wav appendBytes:&outBytes length:4]; - [wav appendData:audioBuffer]; + [wav appendData:_audioBuffer]; - sound = [[NSSound alloc] initWithData:wav]; - [sound play]; + _sound = [[NSSound alloc] initWithData:wav]; + [_sound play]; } - (void)dealloc { - if (audioFrame) av_frame_free(&audioFrame); - if (audioCodecCtx) avcodec_free_context(&audioCodecCtx); - if (swrCtx) swr_free(&swrCtx); + if (_audioFrame) av_frame_free(&_audioFrame); + if (_audioCodecCtx) avcodec_free_context(&_audioCodecCtx); + if (_swrCtx) swr_free(&_swrCtx); [super dealloc]; } + @end @implementation GSMovieView @@ -178,19 +185,19 @@ - (void) dealloc - (void)logStreamMetadata { - AVStream *vs = formatContext->streams[videoStreamIndex]; - double duration = (double)formatContext->duration / AV_TIME_BASE; + AVStream *vs = _formatContext->streams[_videoStreamIndex]; + double duration = (double)_formatContext->duration / AV_TIME_BASE; NSString *info = [NSString stringWithFormat:@"Video: %dx%d %@ %.2fs", - codecContext->width, - codecContext->height, - [NSString stringWithUTF8String:avcodec_get_name(codecContext->codec_id)], + _codecContext->width, + _codecContext->height, + [NSString stringWithUTF8String:avcodec_get_name(_codecContext->codec_id)], duration]; - [metadataLabel setStringValue:info]; + // [_metadataLabel setStringValue:info]; NSLog(@"%@", info); - if (audioStreamIndex != -1) + if (_audioStreamIndex != -1) { - AVCodecParameters *ap = formatContext->streams[audioStreamIndex]->codecpar; + AVCodecParameters *ap = _formatContext->streams[_audioStreamIndex]->codecpar; NSLog(@"Audio codec: %s, sample rate: %d, channels: %d", avcodec_get_name(ap->codec_id), ap->sample_rate, @@ -224,12 +231,11 @@ - (void) prepareDecoder _audioStreamIndex = -1; for (int i = 0; i < _formatContext->nb_streams; i++) { - AVMediaType type = formatContext->streams[i]->codecpar->codec_type; - if (type == AVMEDIA_TYPE_VIDEO && _videoStreamIndex == -1) + if (_formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && _videoStreamIndex == -1) { _videoStreamIndex = i; } - else if (type == AVMEDIA_TYPE_AUDIO && _audioStreamIndex == -1) + else if (_formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && _audioStreamIndex == -1) { _audioStreamIndex = i; } @@ -255,6 +261,8 @@ - (void) prepareDecoder _swsCtx = sws_getContext(_codecContext->width, _codecContext->height, _codecContext->pix_fmt, _codecContext->width, _codecContext->height, AV_PIX_FMT_RGB24, SWS_BILINEAR, NULL, NULL, NULL); + + [self logStreamMetadata]; } - (void) decodeAndDisplayNextFrame From 3ba1f1403bf9b361c407836f85e3d48062dce1d5 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 26 May 2025 17:07:36 -0400 Subject: [PATCH 13/86] Decode audio packets --- Source/GSMovieView.h | 2 ++ Source/GSMovieView.m | 20 +++++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index 35d89daeb5..a4b4b4c416 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -40,6 +40,7 @@ @class NSImage; @class NSTimer; +@class FFmpegAudioPlayer; APPKIT_EXPORT_CLASS @interface GSMovieView : NSMovieView @@ -56,6 +57,7 @@ APPKIT_EXPORT_CLASS int _audioStreamIndex; uint8_t *_buffer; NSTimer *_decodeTimer; + FFmpegAudioPlayer *_audioPlayer; } - (void) updateImage: (NSImage *)image; diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 0e698dd5a9..1ade864db9 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -172,6 +172,7 @@ - (instancetype) initWithFrame: (NSRect)frame _avframeRGB = NULL; _codecContext = NULL; _formatContext = NULL; + _audioPlayer = [[FFmpegAudioPlayer alloc] init]; } return self; } @@ -180,6 +181,7 @@ - (void) dealloc { [self stop: nil]; RELEASE(_currentFrame); + RELEASE(_audioPlayer); [super dealloc]; } @@ -217,6 +219,7 @@ - (void) updateImage: (NSImage *)image { ASSIGN(_currentFrame, image); [self setNeedsDisplay:YES]; + [_audioPlayer finalizeAndPlayBuffer]; } - (void) prepareDecoder @@ -231,18 +234,25 @@ - (void) prepareDecoder _audioStreamIndex = -1; for (int i = 0; i < _formatContext->nb_streams; i++) { - if (_formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && _videoStreamIndex == -1) + if (_formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO + && _videoStreamIndex == -1) { _videoStreamIndex = i; } - else if (_formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && _audioStreamIndex == -1) + else if (_formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO + && _audioStreamIndex == -1) { _audioStreamIndex = i; } } if (_videoStreamIndex == -1) return; - + if (_audioStreamIndex != -1) + { + [_audioPlayer prepareAudioWithFormatContext: _formatContext + streamIndex: _audioStreamIndex]; + } + AVCodecParameters *codecPar = _formatContext->streams[_videoStreamIndex]->codecpar; const AVCodec *codec = avcodec_find_decoder(codecPar->codec_id); @@ -309,6 +319,10 @@ - (void) decodeAndDisplayNextFrame break; } } + else if (packet.stream_index == _audioStreamIndex) + { + [_audioPlayer decodeAudioPacket: &packet]; + } av_packet_unref(&packet); } } From bece0a9f86e0fe842d281d33274cd887099beea9 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 26 May 2025 22:38:37 -0400 Subject: [PATCH 14/86] Add code that plays sound from the video --- Source/GNUmakefile.preamble | 4 +- Source/GSMovieView.h | 5 +- Source/GSMovieView.m | 116 ++++++++++++++++++------------------ Source/NSSound.m | 12 ++-- config.make.in | 5 ++ configure | 6 ++ configure.ac | 4 ++ 7 files changed, 86 insertions(+), 66 deletions(-) diff --git a/Source/GNUmakefile.preamble b/Source/GNUmakefile.preamble index 3e0e318b2d..e6feaad3fb 100644 --- a/Source/GNUmakefile.preamble +++ b/Source/GNUmakefile.preamble @@ -52,7 +52,7 @@ endif ADDITIONAL_OBJCFLAGS = -Wall # Additional flags to pass to the C compiler -ADDITIONAL_CFLAGS = $(MOVIE_BASE_CFLAGS) +ADDITIONAL_CFLAGS += $(MOVIE_BASE_CFLAGS) $(SOUND_CFLAGS) # Additional include directories the compiler should search ADDITIONAL_INCLUDE_DIRS += -I../Headers/Additions -I../Headers \ @@ -62,7 +62,7 @@ ADDITIONAL_INCLUDE_DIRS += -I../Headers/Additions -I../Headers \ # ADDITIONAL_LDFLAGS = # Additional library directories the linker should search -ADDITIONAL_LIB_DIRS = $(MOVIE_BASE_LIBS) +ADDITIONAL_LIB_DIRS += $(MOVIE_BASE_LIBS) $(SOUND_LIBS) # # Sparc systems cannot load tiff files due to some problem compiling diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index a4b4b4c416..de1339db8f 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -30,12 +30,15 @@ #define _GNUstep_H_GSMovieView #import "config.h" - #import "AppKit/NSMovieView.h" +#include + +/* FFmpeg headers */ #include #include #include +#include #include @class NSImage; diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 1ade864db9..f900992006 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -50,106 +50,108 @@ @interface FFmpegAudioPlayer : NSObject AVCodecContext *_audioCodecCtx; AVFrame *_audioFrame; SwrContext *_swrCtx; - NSMutableData *_audioBuffer; - NSSound *_sound; + ao_device *_aoDev; + ao_sample_format _aoFmt; } -- (void)prepareAudioWithFormatContext:(AVFormatContext *)formatCtx streamIndex:(int)audioStreamIndex; +- (void)prepareAudioWithFormatContext:(AVFormatContext *)formatCtx + streamIndex:(int)audioStreamIndex; - (void)decodeAudioPacket:(AVPacket *)packet; @end @implementation FFmpegAudioPlayer -- (void)prepareAudioWithFormatContext:(AVFormatContext *)formatCtx streamIndex:(int)audioStreamIndex +- (void)prepareAudioWithFormatContext:(AVFormatContext *)formatCtx + streamIndex:(int)audioStreamIndex { + ao_initialize(); + int driver = ao_default_driver_id(); + AVCodecParameters *audioPar = formatCtx->streams[audioStreamIndex]->codecpar; AVCodec *audioCodec = avcodec_find_decoder(audioPar->codec_id); + if (!audioCodec) { NSLog(@"Audio codec not found."); return; } + _audioCodecCtx = avcodec_alloc_context3(audioCodec); avcodec_parameters_to_context(_audioCodecCtx, audioPar); + if (avcodec_open2(_audioCodecCtx, audioCodec, NULL) < 0) { - NSLog(@"Failed to open _audio codec."); + NSLog(@"Failed to open audio codec."); return; } _audioFrame = av_frame_alloc(); _swrCtx = swr_alloc_set_opts(NULL, - AV_CH_LAYOUT_STEREO, - AV_SAMPLE_FMT_S16, - _audioCodecCtx->sample_rate, - _audioCodecCtx->channel_layout, - _audioCodecCtx->sample_fmt, - _audioCodecCtx->sample_rate, - 0, NULL); + AV_CH_LAYOUT_STEREO, + AV_SAMPLE_FMT_S16, + _audioCodecCtx->sample_rate, + _audioCodecCtx->channel_layout, + _audioCodecCtx->sample_fmt, + _audioCodecCtx->sample_rate, + 0, NULL); swr_init(_swrCtx); + memset(&_aoFmt, 0, sizeof(ao_sample_format)); + _aoFmt.bits = 16; + _aoFmt.channels = 2; + _aoFmt.rate = _audioCodecCtx->sample_rate; + _aoFmt.byte_format = AO_FMT_NATIVE; + + _aoDev = ao_open_live(driver, &_aoFmt, NULL); + + if (!_aoDev) + NSLog(@"Failed to open AO device."); + NSLog(@"Audio codec: %s, Sample rate: %d, Channels: %d", - audioCodec->name, - audioPar->sample_rate, - audioPar->channels); + audioCodec->name, + audioPar->sample_rate, + audioPar->channels); } - (void)decodeAudioPacket:(AVPacket *)packet { - if (!_audioCodecCtx || !_swrCtx) return; - if (avcodec_send_packet(_audioCodecCtx, packet) < 0) return; + if (!_audioCodecCtx || !_swrCtx || !_aoDev) + return; + + if (avcodec_send_packet(_audioCodecCtx, packet) < 0) + return; + while (avcodec_receive_frame(_audioCodecCtx, _audioFrame) == 0) { int outSamples = _audioFrame->nb_samples; int outBytes = av_samples_get_buffer_size(NULL, 2, outSamples, AV_SAMPLE_FMT_S16, 1); - uint8_t *outBuf = (uint8_t *)malloc(outBytes); + uint8_t *outBuf = (uint8_t *) malloc(outBytes); uint8_t *outPtrs[] = { outBuf }; - + swr_convert(_swrCtx, outPtrs, outSamples, - (const uint8_t **)_audioFrame->data, outSamples); - - [_audioBuffer appendBytes:outBuf length:outBytes]; + (const uint8_t **) _audioFrame->data, outSamples); + + ao_play(_aoDev, (char *) outBuf, outBytes); free(outBuf); } } -- (void)finalizeAndPlayBuffer -{ - int sampleRate = _audioCodecCtx->sample_rate; - int outBytes = (int)[_audioBuffer length]; - int byteRate = sampleRate * 2 * 2; - int blockAlign = 2 * 2; - - NSMutableData *wav = [NSMutableData data]; - [wav appendBytes:"RIFF" length:4]; - uint32_t chunkSize = 36 + outBytes; - [wav appendBytes:&chunkSize length:4]; - [wav appendBytes:"WAVEfmt " length:8]; - - uint32_t subchunk1Size = 16; - [wav appendBytes:&subchunk1Size length:4]; - uint16_t audioFormat = 1, numChannels = 2, bitsPerSample = 16; - [wav appendBytes:&audioFormat length:2]; - [wav appendBytes:&numChannels length:2]; - [wav appendBytes:&sampleRate length:4]; - [wav appendBytes:&byteRate length:4]; - [wav appendBytes:&blockAlign length:2]; - [wav appendBytes:&bitsPerSample length:2]; - - [wav appendBytes:"data" length:4]; - [wav appendBytes:&outBytes length:4]; - [wav appendData:_audioBuffer]; - - _sound = [[NSSound alloc] initWithData:wav]; - [_sound play]; -} - - (void)dealloc { - if (_audioFrame) av_frame_free(&_audioFrame); - if (_audioCodecCtx) avcodec_free_context(&_audioCodecCtx); - if (_swrCtx) swr_free(&_swrCtx); + if (_audioFrame) + av_frame_free(&_audioFrame); + + if (_audioCodecCtx) + avcodec_free_context(&_audioCodecCtx); + + if (_swrCtx) + swr_free(&_swrCtx); + + if (_aoDev) + ao_close(_aoDev); + + ao_shutdown(); [super dealloc]; } @@ -219,7 +221,7 @@ - (void) updateImage: (NSImage *)image { ASSIGN(_currentFrame, image); [self setNeedsDisplay:YES]; - [_audioPlayer finalizeAndPlayBuffer]; + // [_audioPlayer finalizeAndPlayBuffer]; } - (void) prepareDecoder diff --git a/Source/NSSound.m b/Source/NSSound.m index 92ce12956c..d51adbcf3d 100644 --- a/Source/NSSound.m +++ b/Source/NSSound.m @@ -277,9 +277,9 @@ - (id) initWithData: (NSData *)data NSEnumerator *enumerator; Class sourceClass, sinkClass; - - _data = data; - RETAIN(_data); + + // Use new data... + ASSIGN(_data, data); // Search for an GSSoundSource bundle that can play this data. enumerator = [sourcePlugIns objectEnumerator]; @@ -298,9 +298,9 @@ - (id) initWithData: (NSData *)data } } - enumerator = [sinkPlugIns objectEnumerator]; /* FIXME: Grab the first available sink/device for now. In the future - look for what is set in the GSSoundDeviceBundle default first. */ + look for what is set in the GSSoundDeviceBundle default first. */ + enumerator = [sinkPlugIns objectEnumerator]; while ((sinkClass = [enumerator nextObject]) != nil) { if ([sinkClass canInitWithPlaybackDevice: nil]) @@ -335,7 +335,7 @@ - (id) initWithPasteboard: (NSPasteboard *)pasteboard if ([object_getClass(self) canInitWithPasteboard: pasteboard] == YES) { /* FIXME: Should this be @"NSGeneralPboardType" or @"NSSoundPboardType"? - Apple also defines "NSString *NSSoundPboardType". */ + Apple also defines "NSString *NSSoundPboardType". */ NSData *d = [pasteboard dataForType: @"NSGeneralPboardType"]; return [self initWithData: d]; } diff --git a/config.make.in b/config.make.in index b99379ab67..a6c6b704c2 100644 --- a/config.make.in +++ b/config.make.in @@ -19,6 +19,11 @@ BUILD_MOVIE=@BUILD_MOVIE@ MOVIE_BASE_LIBS=@MOVIE_BASE_LIBS@ MOVIE_BASE_CFLAGS=@MOVIE_BASE_CFLAGS@ +# Sound +BUILD_SOUND=@BUILD_SOUND@ +SOUND_LIBS=@SOUND_LIBS@ +SOUND_CFLAGS=@SOUND_CFLAGS@ + # CUPS GSCUPS_CFLAGS = @GSCUPS_CFLAGS@ GSCUPS_LDFLAGS = @GSCUPS_LDFLAGS@ diff --git a/configure b/configure index a3cc348587..9d5d1abc45 100755 --- a/configure +++ b/configure @@ -671,6 +671,8 @@ RECOGNIZER_BASE_CFLAGS RECOGNIZER_BASE_LIBS BUILD_SPEECH_RECOGNIZER BUILD_SPEECH +SOUND_CFLAGS +SOUND_LIBS BUILD_SOUND HAVE_ICU ICU_CFLAGS @@ -6196,9 +6198,13 @@ done # Only if we have both... if test $have_sndfile = yes -a $have_ao = yes -a $enable_sound = yes; then BUILD_SOUND="sound" + SOUND_LIBS=`pkg-config --libs sndfile ao` + SOUND_CFLAGS=`pkg-config --cflags sndfile ao` fi + + #-------------------------------------------------------------------- # NSSpeechSynthesizer #-------------------------------------------------------------------- diff --git a/configure.ac b/configure.ac index 410e8c5f90..952f7d612f 100644 --- a/configure.ac +++ b/configure.ac @@ -543,8 +543,12 @@ AC_CHECK_HEADERS(ao/ao.h, have_ao=yes, have_ao=no) # Only if we have both... if test $have_sndfile = yes -a $have_ao = yes -a $enable_sound = yes; then BUILD_SOUND="sound" + SOUND_LIBS=`pkg-config --libs sndfile ao` + SOUND_CFLAGS=`pkg-config --cflags sndfile ao` fi AC_SUBST(BUILD_SOUND) +AC_SUBST(SOUND_LIBS) +AC_SUBST(SOUND_CFLAGS) #-------------------------------------------------------------------- # NSSpeechSynthesizer From 2cf7378447dcef8f69c5130361f82f7b95f96c63 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 26 May 2025 22:51:42 -0400 Subject: [PATCH 15/86] Slight improvements to sound handling --- Source/GSMovieView.h | 2 ++ Source/GSMovieView.m | 32 ++++++++++++++++++++++++++++---- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index de1339db8f..b2b6c8fd16 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -33,6 +33,7 @@ #import "AppKit/NSMovieView.h" #include +#include /* FFmpeg headers */ #include @@ -40,6 +41,7 @@ #include #include #include +#include @class NSImage; @class NSTimer; diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index f900992006..d04343187c 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -44,20 +44,21 @@ #import "GSMovieView.h" #include - @interface FFmpegAudioPlayer : NSObject { AVCodecContext *_audioCodecCtx; AVFrame *_audioFrame; SwrContext *_swrCtx; ao_device *_aoDev; - ao_sample_format _aoFmt; + ao_sample_format _aoFmt; + int64_t _lastPTS; + int64_t _audioClock; + AVRational _timeBase; } - (void)prepareAudioWithFormatContext:(AVFormatContext *)formatCtx - streamIndex:(int)audioStreamIndex; + streamIndex:(int)audioStreamIndex; - (void)decodeAudioPacket:(AVPacket *)packet; - @end @implementation FFmpegAudioPlayer @@ -108,6 +109,10 @@ - (void)prepareAudioWithFormatContext:(AVFormatContext *)formatCtx if (!_aoDev) NSLog(@"Failed to open AO device."); + _timeBase = formatCtx->streams[audioStreamIndex]->time_base; + _lastPTS = 0; + _audioClock = av_gettime(); + NSLog(@"Audio codec: %s, Sample rate: %d, Channels: %d", audioCodec->name, audioPar->sample_rate, @@ -132,6 +137,25 @@ - (void)decodeAudioPacket:(AVPacket *)packet swr_convert(_swrCtx, outPtrs, outSamples, (const uint8_t **) _audioFrame->data, outSamples); + int64_t currentPTS = _audioFrame->pts; + if (currentPTS != AV_NOPTS_VALUE) + { + int64_t pts_time = av_rescale_q(currentPTS, _timeBase, (AVRational){1, 1000000}); + int64_t now = av_gettime(); + + if (_lastPTS != 0 && pts_time > _lastPTS) + { + int64_t expected_delay = pts_time - _lastPTS; + int64_t actual_delay = now - _audioClock; + int64_t diff = expected_delay - actual_delay; + if (diff > 0 && diff < 500000) + usleep((useconds_t)diff); + } + + _lastPTS = pts_time; + _audioClock = av_gettime(); + } + ao_play(_aoDev, (char *) outBuf, outBytes); free(outBuf); } From 0a8e508d7548bd20e0593b8ca7f1cc010e6912bf Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Tue, 27 May 2025 00:55:13 -0400 Subject: [PATCH 16/86] Move sound to a thread to stop it from being unsteady --- Source/GSMovieView.m | 146 +++++++++++++++++++++++-------------------- 1 file changed, 77 insertions(+), 69 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index d04343187c..d60b815de2 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -31,6 +31,7 @@ #import #import #import +#import #import #import "AppKit/NSColor.h" @@ -44,6 +45,7 @@ #import "GSMovieView.h" #include + @interface FFmpegAudioPlayer : NSObject { AVCodecContext *_audioCodecCtx; @@ -54,48 +56,39 @@ @interface FFmpegAudioPlayer : NSObject int64_t _lastPTS; int64_t _audioClock; AVRational _timeBase; + NSMutableArray *_audioPackets; + NSThread *_audioThread; + BOOL _running; } - (void)prepareAudioWithFormatContext:(AVFormatContext *)formatCtx streamIndex:(int)audioStreamIndex; - (void)decodeAudioPacket:(AVPacket *)packet; +- (void)startAudioThread; +- (void)stopAudioThread; +- (void)submitPacket:(AVPacket *)packet; + @end @implementation FFmpegAudioPlayer -- (void)prepareAudioWithFormatContext:(AVFormatContext *)formatCtx - streamIndex:(int)audioStreamIndex +- (void)prepareAudioWithFormatContext:(AVFormatContext *)formatCtx streamIndex:(int)audioStreamIndex { ao_initialize(); int driver = ao_default_driver_id(); AVCodecParameters *audioPar = formatCtx->streams[audioStreamIndex]->codecpar; AVCodec *audioCodec = avcodec_find_decoder(audioPar->codec_id); - - if (!audioCodec) - { - NSLog(@"Audio codec not found."); - return; - } + if (!audioCodec) return; _audioCodecCtx = avcodec_alloc_context3(audioCodec); avcodec_parameters_to_context(_audioCodecCtx, audioPar); - - if (avcodec_open2(_audioCodecCtx, audioCodec, NULL) < 0) - { - NSLog(@"Failed to open audio codec."); - return; - } + if (avcodec_open2(_audioCodecCtx, audioCodec, NULL) < 0) return; _audioFrame = av_frame_alloc(); - _swrCtx = swr_alloc_set_opts(NULL, - AV_CH_LAYOUT_STEREO, - AV_SAMPLE_FMT_S16, - _audioCodecCtx->sample_rate, - _audioCodecCtx->channel_layout, - _audioCodecCtx->sample_fmt, - _audioCodecCtx->sample_rate, - 0, NULL); + _swrCtx = swr_alloc_set_opts(NULL, AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_S16, _audioCodecCtx->sample_rate, + _audioCodecCtx->channel_layout, _audioCodecCtx->sample_fmt, + _audioCodecCtx->sample_rate, 0, NULL); swr_init(_swrCtx); memset(&_aoFmt, 0, sizeof(ao_sample_format)); @@ -103,29 +96,67 @@ - (void)prepareAudioWithFormatContext:(AVFormatContext *)formatCtx _aoFmt.channels = 2; _aoFmt.rate = _audioCodecCtx->sample_rate; _aoFmt.byte_format = AO_FMT_NATIVE; - _aoDev = ao_open_live(driver, &_aoFmt, NULL); - if (!_aoDev) - NSLog(@"Failed to open AO device."); - _timeBase = formatCtx->streams[audioStreamIndex]->time_base; _lastPTS = 0; _audioClock = av_gettime(); + _audioPackets = [[NSMutableArray alloc] init]; + _running = YES; + _audioThread = [[NSThread alloc] initWithTarget:self selector:@selector(audioThreadEntry) object:nil]; + [_audioThread start]; +} + +- (void)submitPacket:(AVPacket *)packet +{ + NSData *data = [NSData dataWithBytes: packet->data + length: packet->size]; + NSNumber *pts = [NSNumber numberWithInt: (packet->pts)]; + NSDictionary *dict = @{ @"data": data, @"pts": pts }; - NSLog(@"Audio codec: %s, Sample rate: %d, Channels: %d", - audioCodec->name, - audioPar->sample_rate, - audioPar->channels); + @synchronized (_audioPackets) + { + [_audioPackets addObject: dict]; + } } -- (void)decodeAudioPacket:(AVPacket *)packet +- (void)audioThreadEntry { - if (!_audioCodecCtx || !_swrCtx || !_aoDev) - return; + while (_running) + { + @autoreleasepool { + NSDictionary *dict = nil; + @synchronized (_audioPackets) { + if ([_audioPackets count] > 0) + { + dict = [[_audioPackets objectAtIndex:0] retain]; + [_audioPackets removeObjectAtIndex:0]; + } + } + if (dict) + { + NSData *data = dict[@"data"]; + NSNumber *pts = dict[@"pts"]; + + AVPacket packet; + av_init_packet(&packet); + packet.data = (uint8_t *)data.bytes; + packet.size = (int)data.length; + packet.pts = pts.longLongValue; + + [self decodeAudioPacket:&packet]; + [dict release]; + } + else + usleep(1000); + } + } +} - if (avcodec_send_packet(_audioCodecCtx, packet) < 0) - return; +- (void)decodeAudioPacket:(AVPacket *)packet +{ + if (!_audioCodecCtx || !_swrCtx || !_aoDev) return; + if (avcodec_send_packet(_audioCodecCtx, packet) < 0) return; while (avcodec_receive_frame(_audioCodecCtx, _audioFrame) == 0) { @@ -137,25 +168,6 @@ - (void)decodeAudioPacket:(AVPacket *)packet swr_convert(_swrCtx, outPtrs, outSamples, (const uint8_t **) _audioFrame->data, outSamples); - int64_t currentPTS = _audioFrame->pts; - if (currentPTS != AV_NOPTS_VALUE) - { - int64_t pts_time = av_rescale_q(currentPTS, _timeBase, (AVRational){1, 1000000}); - int64_t now = av_gettime(); - - if (_lastPTS != 0 && pts_time > _lastPTS) - { - int64_t expected_delay = pts_time - _lastPTS; - int64_t actual_delay = now - _audioClock; - int64_t diff = expected_delay - actual_delay; - if (diff > 0 && diff < 500000) - usleep((useconds_t)diff); - } - - _lastPTS = pts_time; - _audioClock = av_gettime(); - } - ao_play(_aoDev, (char *) outBuf, outBytes); free(outBuf); } @@ -163,18 +175,16 @@ - (void)decodeAudioPacket:(AVPacket *)packet - (void)dealloc { - if (_audioFrame) - av_frame_free(&_audioFrame); - - if (_audioCodecCtx) - avcodec_free_context(&_audioCodecCtx); - - if (_swrCtx) - swr_free(&_swrCtx); - - if (_aoDev) - ao_close(_aoDev); - + _running = NO; + [_audioThread cancel]; + while (![_audioThread isFinished]) usleep(1000); + RELEASE(_audioThread); + + if (_audioFrame) av_frame_free(&_audioFrame); + if (_audioCodecCtx) avcodec_free_context(&_audioCodecCtx); + if (_swrCtx) swr_free(&_swrCtx); + if (_aoDev) ao_close(_aoDev); + [_audioPackets release]; ao_shutdown(); [super dealloc]; } @@ -245,7 +255,6 @@ - (void) updateImage: (NSImage *)image { ASSIGN(_currentFrame, image); [self setNeedsDisplay:YES]; - // [_audioPlayer finalizeAndPlayBuffer]; } - (void) prepareDecoder @@ -339,7 +348,6 @@ - (void) decodeAndDisplayNextFrame [self performSelectorOnMainThread: @selector(updateImage:) withObject: image waitUntilDone: NO]; - // AUTORELEASE(image); AUTORELEASE(rep); break; @@ -347,7 +355,7 @@ - (void) decodeAndDisplayNextFrame } else if (packet.stream_index == _audioStreamIndex) { - [_audioPlayer decodeAudioPacket: &packet]; + [_audioPlayer submitPacket: &packet]; } av_packet_unref(&packet); } From 8c595f47566c602f564251089a3c3a3581eca824 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Tue, 27 May 2025 11:53:21 -0400 Subject: [PATCH 17/86] Try to sync up audio output --- Source/GSMovieView.h | 1 + Source/GSMovieView.m | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index b2b6c8fd16..ca7acb7026 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -63,6 +63,7 @@ APPKIT_EXPORT_CLASS uint8_t *_buffer; NSTimer *_decodeTimer; FFmpegAudioPlayer *_audioPlayer; + AVRational _videoTimeBase; } - (void) updateImage: (NSImage *)image; diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index d60b815de2..88f9b96c8a 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -67,11 +67,17 @@ - (void)decodeAudioPacket:(AVPacket *)packet; - (void)startAudioThread; - (void)stopAudioThread; - (void)submitPacket:(AVPacket *)packet; +- (int64_t) currentAudioTimeUsec; @end @implementation FFmpegAudioPlayer +- (int64_t) currentAudioTimeUsec +{ + return _audioClock + (av_rescale_q(_lastPTS, _timeBase, (AVRational){1,1000000})); +} + - (void)prepareAudioWithFormatContext:(AVFormatContext *)formatCtx streamIndex:(int)audioStreamIndex { ao_initialize(); @@ -291,6 +297,7 @@ - (void) prepareDecoder AVCodecParameters *codecPar = _formatContext->streams[_videoStreamIndex]->codecpar; const AVCodec *codec = avcodec_find_decoder(codecPar->codec_id); + _videoTimeBase = _formatContext->streams[_videoStreamIndex]->time_base; _codecContext = avcodec_alloc_context3(codec); avcodec_parameters_to_context(_codecContext, codecPar); if (avcodec_open2(_codecContext, codec, NULL) < 0) return; @@ -358,7 +365,15 @@ - (void) decodeAndDisplayNextFrame [_audioPlayer submitPacket: &packet]; } av_packet_unref(&packet); - } + + // Sync on sound stream... + int64_t ptsUsec = av_rescale_q(_avframe->pts, _videoTimeBase, (AVRational){1,1000000}); + int64_t nowUsec = [_audioPlayer currentAudioTimeUsec]; + if (ptsUsec > nowUsec) + { + usleep((unsigned int)(ptsUsec - nowUsec)); + } + } } - (void) drawRect: (NSRect)dirtyRect From 01a68ce6464d01f018dd975703e9831f3dc1c3bf Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Tue, 27 May 2025 13:44:13 -0400 Subject: [PATCH 18/86] Remove 2.0 conventions from code, add volume setting, initialization in NSMovieView --- Source/GSMovieView.m | 87 ++++++++++++++++++++++++++++++-------------- Source/NSMovieView.m | 20 ++++++++++ 2 files changed, 80 insertions(+), 27 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 88f9b96c8a..7d7906b049 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -59,6 +59,7 @@ @interface FFmpegAudioPlayer : NSObject NSMutableArray *_audioPackets; NSThread *_audioThread; BOOL _running; + float _volume; } - (void)prepareAudioWithFormatContext:(AVFormatContext *)formatCtx @@ -68,6 +69,7 @@ - (void)startAudioThread; - (void)stopAudioThread; - (void)submitPacket:(AVPacket *)packet; - (int64_t) currentAudioTimeUsec; +- (void) setVolume: (float)volume; @end @@ -118,7 +120,9 @@ - (void)submitPacket:(AVPacket *)packet NSData *data = [NSData dataWithBytes: packet->data length: packet->size]; NSNumber *pts = [NSNumber numberWithInt: (packet->pts)]; - NSDictionary *dict = @{ @"data": data, @"pts": pts }; + NSDictionary *dict = + [NSDictionary dictionaryWithObjectsAndKeys: data, @"data", + pts, @"pts", nil]; @synchronized (_audioPackets) { @@ -130,32 +134,33 @@ - (void)audioThreadEntry { while (_running) { - @autoreleasepool { - NSDictionary *dict = nil; - @synchronized (_audioPackets) { - if ([_audioPackets count] > 0) - { - dict = [[_audioPackets objectAtIndex:0] retain]; - [_audioPackets removeObjectAtIndex:0]; - } - } - if (dict) - { - NSData *data = dict[@"data"]; - NSNumber *pts = dict[@"pts"]; - - AVPacket packet; - av_init_packet(&packet); - packet.data = (uint8_t *)data.bytes; - packet.size = (int)data.length; - packet.pts = pts.longLongValue; - - [self decodeAudioPacket:&packet]; - [dict release]; - } - else - usleep(1000); - } + CREATE_AUTORELEASE_POOL(pool); + NSDictionary *dict = nil; + @synchronized (_audioPackets) + { + if ([_audioPackets count] > 0) + { + dict = [[_audioPackets objectAtIndex:0] retain]; + [_audioPackets removeObjectAtIndex:0]; + } + } + + // Unpack the data from the dictionary... + if (dict) + { + NSData *data = [dict objectForKey: @"data"]; + NSNumber *pts = [dict objectForKey: @"pts"]; + + AVPacket packet; + av_init_packet(&packet); + packet.data = (uint8_t *)[data bytes]; + packet.size = (int)[data length]; + packet.pts = [pts longLongValue]; + + [self decodeAudioPacket:&packet]; + RELEASE(dict); + } + RELEASE(pool); } } @@ -174,11 +179,25 @@ - (void)decodeAudioPacket:(AVPacket *)packet swr_convert(_swrCtx, outPtrs, outSamples, (const uint8_t **) _audioFrame->data, outSamples); + // Apply volume + int16_t *samples = (int16_t *)outBuf; + for (int i = 0; i < outBytes / 2; ++i) + { + samples[i] = samples[i] * _volume; + } + ao_play(_aoDev, (char *) outBuf, outBytes); free(outBuf); } } +- (void)setVolume:(float)volume +{ + if (volume < 0.0) volume = 0.0; + if (volume > 1.0) volume = 1.0; + _volume = volume; +} + - (void)dealloc { _running = NO; @@ -290,6 +309,7 @@ - (void) prepareDecoder if (_videoStreamIndex == -1) return; if (_audioStreamIndex != -1) { + [_audioPlayer setVolume: [super volume]]; [_audioPlayer prepareAudioWithFormatContext: _formatContext streamIndex: _audioStreamIndex]; } @@ -454,4 +474,17 @@ - (void) stop: (id)sender } } +- (void) setVolume: (float)volume +{ + [super setVolume: volume]; + [_audioPlayer setVolume: volume]; +} + +- (NSRect) movieRect +{ + return NSMakeRect(0.0, 0.0, + (float)_codecContext->width, + (float)_codecContext->height); +} + @end diff --git a/Source/NSMovieView.m b/Source/NSMovieView.m index e51d8bde09..289e7ec243 100644 --- a/Source/NSMovieView.m +++ b/Source/NSMovieView.m @@ -60,6 +60,25 @@ + (id) allocWithZone: (NSZone *)zone } #endif +- (instancetype) initWithFrame: (NSRect)frame +{ + self = [super initWithFrame: frame]; + if (self != nil) + { + _movie = nil; + _playing = NO; + _rate = 0.0; + _volume = 1.0; + _flags.muted = NO; + _flags.loopMode = NSQTMovieNormalPlayback; + _flags.plays_selection_only = NO; + _flags.plays_every_frame = YES; + _flags.is_controller_visible = YES; + _flags.editable = NO; + } + return self; +} + - (void) setMovie: (NSMovie*)movie { ASSIGN(_movie, movie); @@ -196,6 +215,7 @@ - (void) resizeWithMagnification: (float)magnification { //FIXME } + - (NSSize) sizeForMagnification: (float)magnification { //FIXME From bc2d382e1a89d2eaaed2cf9d888b5de6df58a101 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Tue, 27 May 2025 18:17:54 -0400 Subject: [PATCH 19/86] Fix warnings, and make audio a little smoother --- Source/GSMovieView.m | 267 +++++++++++++++++++++++++++---------------- 1 file changed, 168 insertions(+), 99 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 7d7906b049..7aac200a82 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -46,6 +46,38 @@ #include +static NSDictionary *NSDictionaryFromAVPacket(AVPacket *packet) +{ + NSData *data = [NSData dataWithBytes:packet->data length:packet->size]; + NSNumber *pts = [NSNumber numberWithLongLong:packet->pts]; + NSNumber *duration = [NSNumber numberWithInt:packet->duration]; + NSNumber *flags = [NSNumber numberWithInt:packet->flags]; + + return [NSDictionary dictionaryWithObjectsAndKeys: + data, @"data", + pts, @"pts", + duration, @"duration", + flags, @"flags", + nil]; +} + +static AVPacket AVPacketFromNSDictionary(NSDictionary *dict) +{ + NSData *data = [dict objectForKey:@"data"]; + NSNumber *pts = [dict objectForKey:@"pts"]; + NSNumber *duration = [dict objectForKey:@"duration"]; + NSNumber *flags = [dict objectForKey:@"flags"]; + + AVPacket *packet = av_packet_alloc(); + packet->data = (uint8_t *)[data bytes]; + packet->size = (int)[data length]; + packet->pts = [pts longLongValue]; + packet->duration = [duration intValue]; + packet->flags = [flags intValue]; + + return *packet; +} + @interface FFmpegAudioPlayer : NSObject { AVCodecContext *_audioCodecCtx; @@ -59,75 +91,72 @@ @interface FFmpegAudioPlayer : NSObject NSMutableArray *_audioPackets; NSThread *_audioThread; BOOL _running; - float _volume; + float _volume; /* 0.0 to 1.0 */ + BOOL _started; } -- (void)prepareAudioWithFormatContext:(AVFormatContext *)formatCtx +- (void) prepareAudioWithFormatContext:(AVFormatContext *)formatCtx streamIndex:(int)audioStreamIndex; -- (void)decodeAudioPacket:(AVPacket *)packet; -- (void)startAudioThread; -- (void)stopAudioThread; -- (void)submitPacket:(AVPacket *)packet; -- (int64_t) currentAudioTimeUsec; +- (void) decodeAudioPacket:(AVPacket *)packet; +- (void) startAudioThread; +- (void) stopAudioThread; - (void) setVolume: (float)volume; @end @implementation FFmpegAudioPlayer -- (int64_t) currentAudioTimeUsec -{ - return _audioClock + (av_rescale_q(_lastPTS, _timeBase, (AVRational){1,1000000})); -} - -- (void)prepareAudioWithFormatContext:(AVFormatContext *)formatCtx streamIndex:(int)audioStreamIndex +- (void) prepareAudioWithFormatContext:(AVFormatContext *)formatCtx + streamIndex:(int)audioStreamIndex { ao_initialize(); int driver = ao_default_driver_id(); - + int out_channels = 2; + AVCodecParameters *audioPar = formatCtx->streams[audioStreamIndex]->codecpar; - AVCodec *audioCodec = avcodec_find_decoder(audioPar->codec_id); - if (!audioCodec) return; + const AVCodec *audioCodec = avcodec_find_decoder(audioPar->codec_id); + + if (!audioCodec) + { + NSLog(@"Audio codec not found."); + return; + } _audioCodecCtx = avcodec_alloc_context3(audioCodec); avcodec_parameters_to_context(_audioCodecCtx, audioPar); - if (avcodec_open2(_audioCodecCtx, audioCodec, NULL) < 0) return; + + if (avcodec_open2(_audioCodecCtx, audioCodec, NULL) < 0) + { + NSLog(@"Failed to open audio codec."); + return; + } _audioFrame = av_frame_alloc(); - _swrCtx = swr_alloc_set_opts(NULL, AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_S16, _audioCodecCtx->sample_rate, - _audioCodecCtx->channel_layout, _audioCodecCtx->sample_fmt, - _audioCodecCtx->sample_rate, 0, NULL); + swr_alloc_set_opts2(&_swrCtx, + &(AVChannelLayout){ .order = AV_CHANNEL_ORDER_NATIVE, + .nb_channels = out_channels, + .u.mask = AV_CH_LAYOUT_STEREO }, + AV_SAMPLE_FMT_S16, + _audioCodecCtx->sample_rate, + &_audioCodecCtx->ch_layout, + _audioCodecCtx->sample_fmt, + _audioCodecCtx->sample_rate, + 0, NULL); swr_init(_swrCtx); memset(&_aoFmt, 0, sizeof(ao_sample_format)); _aoFmt.bits = 16; - _aoFmt.channels = 2; + _aoFmt.channels = out_channels; _aoFmt.rate = _audioCodecCtx->sample_rate; _aoFmt.byte_format = AO_FMT_NATIVE; - _aoDev = ao_open_live(driver, &_aoFmt, NULL); + _aoDev = ao_open_live(driver, &_aoFmt, NULL); _timeBase = formatCtx->streams[audioStreamIndex]->time_base; _lastPTS = 0; _audioClock = av_gettime(); _audioPackets = [[NSMutableArray alloc] init]; _running = YES; - _audioThread = [[NSThread alloc] initWithTarget:self selector:@selector(audioThreadEntry) object:nil]; - [_audioThread start]; -} - -- (void)submitPacket:(AVPacket *)packet -{ - NSData *data = [NSData dataWithBytes: packet->data - length: packet->size]; - NSNumber *pts = [NSNumber numberWithInt: (packet->pts)]; - NSDictionary *dict = - [NSDictionary dictionaryWithObjectsAndKeys: data, @"data", - pts, @"pts", nil]; - - @synchronized (_audioPackets) - { - [_audioPackets addObject: dict]; - } + [self startAudioThread]; } - (void)audioThreadEntry @@ -135,39 +164,57 @@ - (void)audioThreadEntry while (_running) { CREATE_AUTORELEASE_POOL(pool); - NSDictionary *dict = nil; - @synchronized (_audioPackets) - { - if ([_audioPackets count] > 0) - { - dict = [[_audioPackets objectAtIndex:0] retain]; - [_audioPackets removeObjectAtIndex:0]; - } - } - - // Unpack the data from the dictionary... - if (dict) - { - NSData *data = [dict objectForKey: @"data"]; - NSNumber *pts = [dict objectForKey: @"pts"]; - - AVPacket packet; - av_init_packet(&packet); - packet.data = (uint8_t *)[data bytes]; - packet.size = (int)[data length]; - packet.pts = [pts longLongValue]; - - [self decodeAudioPacket:&packet]; - RELEASE(dict); - } + { + NSDictionary *dict = nil; + + @synchronized (_audioPackets) + { + if (!_started && [_audioPackets count] < 5) + { + usleep(5000); + continue; + } + if ([_audioPackets count] > 0) + { + dict = [[_audioPackets objectAtIndex:0] retain]; + [_audioPackets removeObjectAtIndex:0]; + } + } + + if (!_started && dict) + { + _audioClock = av_gettime(); + _started = YES; + } + + if (dict) + { + AVPacket packet = AVPacketFromNSDictionary(dict); + int64_t packetTime = av_rescale_q(packet.pts, _timeBase, (AVRational){1, 1000000}); + int64_t now = av_gettime() - _audioClock; + int64_t delay = packetTime - now; + if (delay > 0) + usleep((useconds_t)delay); + + [self decodeAudioPacket:&packet]; + [dict release]; + } + else + { + usleep(1000); + } + } RELEASE(pool); } } - (void)decodeAudioPacket:(AVPacket *)packet { - if (!_audioCodecCtx || !_swrCtx || !_aoDev) return; - if (avcodec_send_packet(_audioCodecCtx, packet) < 0) return; + if (!_audioCodecCtx || !_swrCtx || !_aoDev) + return; + + if (avcodec_send_packet(_audioCodecCtx, packet) < 0) + return; while (avcodec_receive_frame(_audioCodecCtx, _audioFrame) == 0) { @@ -177,11 +224,13 @@ - (void)decodeAudioPacket:(AVPacket *)packet uint8_t *outPtrs[] = { outBuf }; swr_convert(_swrCtx, outPtrs, outSamples, - (const uint8_t **) _audioFrame->data, outSamples); + (const uint8_t **) _audioFrame->data, + outSamples); // Apply volume int16_t *samples = (int16_t *)outBuf; - for (int i = 0; i < outBytes / 2; ++i) + int i = 0; + for (i = 0; i < outBytes / 2; ++i) { samples[i] = samples[i] * _volume; } @@ -191,6 +240,31 @@ - (void)decodeAudioPacket:(AVPacket *)packet } } +- (void)submitPacket:(AVPacket *)packet +{ + NSDictionary *dict = NSDictionaryFromAVPacket(packet); + @synchronized (_audioPackets) + { + [_audioPackets addObject:dict]; + } +} + +- (void)startAudioThread +{ + _audioThread = [[NSThread alloc] initWithTarget:self selector:@selector(audioThreadEntry) object:nil]; + [_audioThread start]; +} + +- (void)stopAudioThread +{ + _running = NO; + [_audioThread cancel]; + while (![_audioThread isFinished]) + usleep(1000); + [_audioThread release]; + _audioThread = nil; +} + - (void)setVolume:(float)volume { if (volume < 0.0) volume = 0.0; @@ -200,16 +274,22 @@ - (void)setVolume:(float)volume - (void)dealloc { - _running = NO; - [_audioThread cancel]; - while (![_audioThread isFinished]) usleep(1000); - RELEASE(_audioThread); + [self stopAudioThread]; + + if (_audioFrame) + av_frame_free(&_audioFrame); + + if (_audioCodecCtx) + avcodec_free_context(&_audioCodecCtx); + + if (_swrCtx) + swr_free(&_swrCtx); + + if (_aoDev) + ao_close(_aoDev); - if (_audioFrame) av_frame_free(&_audioFrame); - if (_audioCodecCtx) avcodec_free_context(&_audioCodecCtx); - if (_swrCtx) swr_free(&_swrCtx); - if (_aoDev) ao_close(_aoDev); [_audioPackets release]; + ao_shutdown(); [super dealloc]; } @@ -248,7 +328,6 @@ - (void) dealloc - (void)logStreamMetadata { - AVStream *vs = _formatContext->streams[_videoStreamIndex]; double duration = (double)_formatContext->duration / AV_TIME_BASE; NSString *info = [NSString stringWithFormat:@"Video: %dx%d %@ %.2fs", _codecContext->width, @@ -261,10 +340,10 @@ - (void)logStreamMetadata if (_audioStreamIndex != -1) { AVCodecParameters *ap = _formatContext->streams[_audioStreamIndex]->codecpar; - NSLog(@"Audio codec: %s, sample rate: %d, channels: %d", + NSLog(@"Audio codec: %s, sample rate: %d", avcodec_get_name(ap->codec_id), - ap->sample_rate, - ap->channels); + ap->sample_rate); + // ap->channels); } } @@ -339,19 +418,17 @@ - (void) prepareDecoder - (void) decodeAndDisplayNextFrame { - AVPacket packet; + AVPacket *packet = av_packet_alloc(); + packet->data = NULL; + packet->size = 0; - av_init_packet(&packet); - packet.data = NULL; - packet.size = 0; - - while (av_read_frame(_formatContext, &packet) >= 0) + while (av_read_frame(_formatContext, packet) >= 0) { if (!_playing) break; - if (packet.stream_index == _videoStreamIndex) + if (packet->stream_index == _videoStreamIndex) { - avcodec_send_packet(_codecContext, &packet); + avcodec_send_packet(_codecContext, packet); if (avcodec_receive_frame(_codecContext, _avframe) == 0) { sws_scale(_swsCtx, (const uint8_t * const *)_avframe->data, _avframe->linesize, 0, @@ -380,19 +457,11 @@ - (void) decodeAndDisplayNextFrame break; } } - else if (packet.stream_index == _audioStreamIndex) + else if (packet->stream_index == _audioStreamIndex) { - [_audioPlayer submitPacket: &packet]; + [_audioPlayer submitPacket: packet]; } - av_packet_unref(&packet); - - // Sync on sound stream... - int64_t ptsUsec = av_rescale_q(_avframe->pts, _videoTimeBase, (AVRational){1,1000000}); - int64_t nowUsec = [_audioPlayer currentAudioTimeUsec]; - if (ptsUsec > nowUsec) - { - usleep((unsigned int)(ptsUsec - nowUsec)); - } + av_packet_unref(packet); } } From b123e82062069066a09d07b34a0e51e426136be4 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Tue, 27 May 2025 20:22:06 -0400 Subject: [PATCH 20/86] Use GNUstep define for RELEASE --- Source/GSMovieView.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 7aac200a82..535098a157 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -288,7 +288,7 @@ - (void)dealloc if (_aoDev) ao_close(_aoDev); - [_audioPackets release]; + RELEASE(_audioPackets); ao_shutdown(); [super dealloc]; From 672ff2aa5cd51f1a23866eb7fadeed77141e0a84 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Thu, 29 May 2025 12:16:38 -0400 Subject: [PATCH 21/86] Refactor NSMovieView to delegate certain methods to the subclass, in GSMovieView move decoding entirely to threads --- Source/GSMovieView.h | 35 +++-- Source/GSMovieView.m | 337 ++++++++++++++++++++++++++++++++++++++----- Source/NSMovieView.m | 20 +-- 3 files changed, 318 insertions(+), 74 deletions(-) diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index ca7acb7026..17b6051a14 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -50,25 +50,30 @@ APPKIT_EXPORT_CLASS @interface GSMovieView : NSMovieView { + NSMutableArray *_videoPackets; + NSThread *_videoThread; + NSThread *_feedThread; NSImage *_currentFrame; -#ifdef HAVE_AVCODEC - AVFormatContext *_formatContext; - AVCodecContext *_codecContext; - AVFrame *_avframe; - AVFrame *_avframeRGB; - struct SwsContext *_swsCtx; -#endif - int _videoStreamIndex; - int _audioStreamIndex; - uint8_t *_buffer; - NSTimer *_decodeTimer; FFmpegAudioPlayer *_audioPlayer; - AVRational _videoTimeBase; + + AVCodecContext *_videoCodecCtx; + AVFrame *_videoFrame; + struct SwsContext *_swsCtx; + AVRational _timeBase; + + BOOL _running; + BOOL _started; + int64_t _videoClock; } -- (void) updateImage: (NSImage *)image; -- (void) prepareDecoder; -- (void) decodeAndDisplayNextFrame; +- (void) prepareVideoWithFormatContext: (AVFormatContext *)formatCtx + streamIndex: (int)videoStreamIndex; +- (void) submitVideoPacket: (AVPacket *)packet; +- (void) decodeVideoPacket: (AVPacket *)packet; +- (void) start; +- (void) stop; +- (void) feed; +// - (void) logStreamMetadata; @end diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 535098a157..d0c7a7a7df 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -303,29 +303,40 @@ - (instancetype) initWithFrame: (NSRect)frame self = [super initWithFrame: frame]; if (self != nil) { - _videoStreamIndex = -1; - _audioStreamIndex = -1; - _decodeTimer = nil; _currentFrame = nil; - _buffer = NULL; - _swsCtx = NULL; - _avframe = NULL; - _avframeRGB = NULL; - _codecContext = NULL; - _formatContext = NULL; + _videoThread = nil; + _feedThread = nil; _audioPlayer = [[FFmpegAudioPlayer alloc] init]; + _videoPackets = RETAIN([[NSMutableArray alloc] init]); + _running = NO; + _started = NO; + _videoClock = 0; + _videoCodecCtx = 0; + _swsCtx = NULL; } return self; } -- (void) dealloc + +- (void)dealloc { [self stop: nil]; - RELEASE(_currentFrame); - RELEASE(_audioPlayer); + + if (_videoFrame) + av_frame_free(&_videoFrame); + if (_videoCodecCtx) + avcodec_free_context(&_videoCodecCtx); + if (_swsCtx) + sws_freeContext(_swsCtx); + + DESTROY(_videoPackets); + // DESTROY(_currentFrame); + // DESTROY(_audioPlayer); + [super dealloc]; } +/* - (void)logStreamMetadata { double duration = (double)_formatContext->duration / AV_TIME_BASE; @@ -334,26 +345,19 @@ - (void)logStreamMetadata _codecContext->height, [NSString stringWithUTF8String:avcodec_get_name(_codecContext->codec_id)], duration]; - // [_metadataLabel setStringValue:info]; - NSLog(@"%@", info); if (_audioStreamIndex != -1) { AVCodecParameters *ap = _formatContext->streams[_audioStreamIndex]->codecpar; - NSLog(@"Audio codec: %s, sample rate: %d", - avcodec_get_name(ap->codec_id), - ap->sample_rate); - // ap->channels); + NSString *audioInfo = [NSString stringWithFormat: @"Audio codec: %s, sample rate: %d", + avcodec_get_name(ap->codec_id), + ap->sample_rate]; + info = [NSString stringWithFormat: @"%@ %@", info, audioInfo]; } -} -- (void) resetDecoder -{ - [self stop: nil]; - RELEASE(_currentFrame); - _videoStreamIndex = -1; - _audioStreamIndex = -1; + NSLog(@"%@", info); } +*/ - (void) updateImage: (NSImage *)image { @@ -361,6 +365,272 @@ - (void) updateImage: (NSImage *)image [self setNeedsDisplay:YES]; } +- (IBAction) start: (id)sender +{ + _feedThread = RETAIN([[NSThread alloc] initWithTarget:self selector:@selector(feed) object:nil]); + [_feedThread start]; +} + +- (IBAction) stop: (id)sender +{ + [_feedThread cancel]; + [self stop]; + DESTROY(_feedThread); +} + +- (void) drawRect: (NSRect)dirtyRect +{ + [super drawRect: dirtyRect]; + if (_currentFrame) + { + [_currentFrame drawInRect: [self bounds]]; + } +} + +- (void) feed +{ + NSMovie *movie = [self movie]; + NSURL *url = [movie URL]; + const char *path = [[url path] UTF8String]; + NSLog(@"[Info] Opening file: %s | Timestamp: %ld", path, av_gettime()); + avformat_network_init(); + + AVFormatContext *formatCtx = NULL; + if (avformat_open_input(&formatCtx, path, NULL, NULL) != 0) + { + NSLog(@"[Error] Could not open file: %s | Timestamp: %ld", path, av_gettime()); + return; + } + + if (avformat_find_stream_info(formatCtx, NULL) < 0) + { + NSLog(@"[Error] Could not find stream info. | Timestamp: %ld", av_gettime()); + avformat_close_input(&formatCtx); + return; + } + + int videoStream = -1; + for (unsigned int i = 0; i < formatCtx->nb_streams; i++) + { + if (formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) + { + videoStream = i; + break; + } + } + + int audioStream = -1; + for (unsigned int i = 0; i < formatCtx->nb_streams; i++) + { + if (formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) + { + audioStream = i; + break; + } + } + + if (videoStream == -1) + { + NSLog(@"[Error] No video stream found. | Timestamp: %ld", av_gettime()); + avformat_close_input(&formatCtx); + return; + } + + // If it's video only we just log it and continue... + if (audioStream == -1) + { + NSLog(@"[Error] No audio stream found. | Timestamp: %ld", av_gettime()); + } + + [self prepareVideoWithFormatContext:formatCtx streamIndex:videoStream]; + // usleep(1000); + // [self start]; + + AVPacket packet; + while (av_read_frame(formatCtx, &packet) >= 0) + { + if (packet.stream_index == videoStream) + [self submitVideoPacket:&packet]; + + /* + if (packet.stream_index == audioStream) + [_audioPlayer submitVideoPacket:&packet]; + */ + av_packet_unref(&packet); + } + + [self start]; + + // [self stop]; + avformat_close_input(&formatCtx); +} + +- (void)prepareVideoWithFormatContext:(AVFormatContext *)formatCtx streamIndex:(int)videoStreamIndex +{ + AVCodecParameters *videoPar = formatCtx->streams[videoStreamIndex]->codecpar; + const AVCodec *videoCodec = avcodec_find_decoder(videoPar->codec_id); + if (!videoCodec) + { + NSLog(@"[Error] Unsupported video codec. | Timestamp: %ld", av_gettime()); + return; + } + + _videoCodecCtx = avcodec_alloc_context3(videoCodec); + avcodec_parameters_to_context(_videoCodecCtx, videoPar); + if (avcodec_open2(_videoCodecCtx, videoCodec, NULL) < 0) + { + NSLog(@"[Error] Failed to open video codec. | Timestamp: %ld", av_gettime()); + return; + } + + _videoFrame = av_frame_alloc(); + _swsCtx = sws_getContext(videoPar->width, videoPar->height, _videoCodecCtx->pix_fmt, + videoPar->width, videoPar->height, AV_PIX_FMT_RGB24, + SWS_BILINEAR, NULL, NULL, NULL); + + _timeBase = formatCtx->streams[videoStreamIndex]->time_base; + _videoPackets = RETAIN([[NSMutableArray alloc] init]); + _videoClock = av_gettime(); + _running = NO; + _started = NO; +} + +- (void) start +{ + NSLog(@"[GSMovieView] Starting video thread | Timestamp: %ld", av_gettime()); + if (!_running) + { + _running = YES; + _videoThread = RETAIN([[NSThread alloc] initWithTarget:self selector:@selector(videoThreadEntry) object:nil]); + [_videoThread start]; + } +} + +- (void) stop +{ + NSLog(@"[GSMovieView] Stopping video thread | Timestamp: %ld", av_gettime()); + if (_running) + { + _running = NO; + [_videoThread cancel]; + while (![_videoThread isFinished]) + usleep(1000); + DESTROY(_videoThread); + } +} + +- (void)submitVideoPacket:(AVPacket *)packet +{ + NSDictionary *dict = NSDictionaryFromAVPacket(packet); + @synchronized (_videoPackets) + { + [_videoPackets addObject:dict]; + } +} + +- (void)videoThreadEntry +{ + while (_running) + { + CREATE_AUTORELEASE_POOL(pool); + { + NSDictionary *dict = nil; + + @synchronized (_videoPackets) + { + if (!_started && [_videoPackets count] < 3) + { + usleep(5000); + [pool release]; + continue; + } + if ([_videoPackets count] > 0) + { + dict = RETAIN([_videoPackets objectAtIndex:0]); + [_videoPackets removeObjectAtIndex:0]; + } + } + + if (!_started && dict) + { + _videoClock = av_gettime(); + _started = YES; + } + + if (dict) + { + // NSLog(@"[GSMovieView] Rendering frame PTS: %ld | Delay: %ld us", packet.pts, delay); + AVPacket packet = AVPacketFromNSDictionary(dict); + + int64_t packetTime = av_rescale_q(packet.pts, _timeBase, (AVRational){1, 1000000}); + int64_t now = av_gettime() - _videoClock; + int64_t delay = packetTime - now; + if (delay > 0) + usleep((useconds_t)delay); + + [self decodeVideoPacket:&packet]; + RELEASE(dict); + } + else + { + usleep(1000); + } + RELEASE(pool); + } + } +} + +- (void)decodeVideoPacket:(AVPacket *)packet +{ + if (!_videoCodecCtx || !_swsCtx) + return; + + if (avcodec_send_packet(_videoCodecCtx, packet) < 0) + return; + + while (avcodec_receive_frame(_videoCodecCtx, _videoFrame) == 0) + { + uint8_t *rgbData[1]; + int rgbLineSize[1]; + + int width = _videoCodecCtx->width; + int height = _videoCodecCtx->height; + + rgbLineSize[0] = width * 3; + rgbData[0] = (uint8_t *)malloc(height * rgbLineSize[0]); + + sws_scale(_swsCtx, + (const uint8_t * const *)_videoFrame->data, + _videoFrame->linesize, + 0, + height, + rgbData, + rgbLineSize); + + NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] + initWithBitmapDataPlanes: &rgbData[0] + pixelsWide: width + pixelsHigh: height + bitsPerSample: 8 + samplesPerPixel: 3 + hasAlpha: NO + isPlanar: NO + colorSpaceName: NSCalibratedRGBColorSpace + bytesPerRow: rgbLineSize[0] + bitsPerPixel: 24]; + + NSImage *image = [[NSImage alloc] initWithSize: NSMakeSize(width, height)]; + [image addRepresentation: bitmap]; + [self performSelectorOnMainThread: @selector(updateImage:) + withObject: image + waitUntilDone: NO]; + + RELEASE(bitmap); + free(rgbData[0]); + } +} + +/* - (void) prepareDecoder { NSString *moviePath = [[_movie URL] path]; @@ -465,21 +735,6 @@ - (void) decodeAndDisplayNextFrame } } -- (void) drawRect: (NSRect)dirtyRect -{ - [super drawRect: dirtyRect]; - if (_currentFrame) - { - [_currentFrame drawInRect: [self bounds]]; - } -} - -- (void) setMovie: (NSMovie*)movie -{ - [self resetDecoder]; - [super setMovie: movie]; - [self prepareDecoder]; -} - (void) start: (id)sender { @@ -556,4 +811,6 @@ - (NSRect) movieRect (float)_codecContext->height); } +*/ + @end diff --git a/Source/NSMovieView.m b/Source/NSMovieView.m index 289e7ec243..a808af6794 100644 --- a/Source/NSMovieView.m +++ b/Source/NSMovieView.m @@ -66,7 +66,6 @@ - (instancetype) initWithFrame: (NSRect)frame if (self != nil) { _movie = nil; - _playing = NO; _rate = 0.0; _volume = 1.0; _flags.muted = NO; @@ -91,42 +90,35 @@ - (NSMovie*) movie - (void) start: (id)sender { - _playing = YES; } - (void) stop: (id)sender { - _playing = NO; } - (BOOL) isPlaying { - return _playing; + return NO; } - (void) gotoPosterFrame: (id)sender { - //FIXME } - (void) gotoBeginning: (id)sender { - //FIXME } - (void) gotoEnd: (id)sender { - //FIXME } - (void) stepForward: (id)sender { - //FIXME } - (void) stepBack: (id)sender { - //FIXME } - (void) setRate: (float)rate @@ -191,13 +183,11 @@ - (BOOL) playsEveryFrame - (void) showController: (BOOL)show adjustingSize: (BOOL)adjustSize { - //FIXME _flags.is_controller_visible = show; } - (void*) movieController { - //FIXME return NULL; } @@ -213,12 +203,10 @@ - (NSRect) movieRect - (void) resizeWithMagnification: (float)magnification { - //FIXME } - (NSSize) sizeForMagnification: (float)magnification { - //FIXME return NSMakeSize(0, 0); } @@ -234,32 +222,26 @@ - (BOOL) isEditable - (void) cut: (id)sender { - //FIXME } - (void) copy: (id)sender { - //FIXME } - (void) paste: (id)sender { - //FIXME } - (void) clear: (id)sender { - //FIXME } - (void) undo: (id)sender { - //FIXME } - (void) selectAll: (id)sender { - //FIXME } @end From 410713aab4f1579e900e7981be7ab17dc56a588a Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Thu, 29 May 2025 14:10:31 -0400 Subject: [PATCH 22/86] Add a delay of 1000 frames before we start the player thread. --- Source/GSMovieView.m | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index d0c7a7a7df..91d2132e38 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -443,12 +443,17 @@ - (void) feed } [self prepareVideoWithFormatContext:formatCtx streamIndex:videoStream]; - // usleep(1000); - // [self start]; AVPacket packet; + int64_t i = 0; while (av_read_frame(formatCtx, &packet) >= 0) { + // After 100 frames, start the thread... + if (i == 1000) + { + [self start]; + } + if (packet.stream_index == videoStream) [self submitVideoPacket:&packet]; @@ -457,11 +462,16 @@ - (void) feed [_audioPlayer submitVideoPacket:&packet]; */ av_packet_unref(&packet); + i++; } - [self start]; + // if we had a very short video... play it. + if (i < 1000) + { + NSLog(@"[GSMovieView] Starting short video... | Timestamp: %ld", av_gettime()); + [self start]; + } - // [self stop]; avformat_close_input(&formatCtx); } From c8ffb3c0b2e0fac48069c6d8a91593a5a12914fa Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Thu, 29 May 2025 14:40:56 -0400 Subject: [PATCH 23/86] Add audio support --- Source/GSMovieView.m | 322 +++++++++++-------------------------------- 1 file changed, 79 insertions(+), 243 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 91d2132e38..cc3d9e56ff 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -98,13 +98,53 @@ @interface FFmpegAudioPlayer : NSObject - (void) prepareAudioWithFormatContext:(AVFormatContext *)formatCtx streamIndex:(int)audioStreamIndex; - (void) decodeAudioPacket:(AVPacket *)packet; -- (void) startAudioThread; -- (void) stopAudioThread; +- (void) start; +- (void) stop; - (void) setVolume: (float)volume; @end @implementation FFmpegAudioPlayer +- (instancetype) init +{ + self = [super init]; + if (self != nil) + { + _audioCodecCtx = NULL; + _audioFrame = NULL; + _swrCtx = NULL; + _lastPTS = 0; + _audioClock = 0; + _audioPackets = nil; + _audioThread = nil; + _running = NO; + _volume = 1.0; + _started = NO; + } + return self; +} + +- (void)dealloc +{ + [self stop]; + + if (_audioFrame) + av_frame_free(&_audioFrame); + + if (_audioCodecCtx) + avcodec_free_context(&_audioCodecCtx); + + if (_swrCtx) + swr_free(&_swrCtx); + + if (_aoDev) + ao_close(_aoDev); + + RELEASE(_audioPackets); + + ao_shutdown(); + [super dealloc]; +} - (void) prepareAudioWithFormatContext:(AVFormatContext *)formatCtx streamIndex:(int)audioStreamIndex @@ -156,7 +196,7 @@ - (void) prepareAudioWithFormatContext:(AVFormatContext *)formatCtx _audioClock = av_gettime(); _audioPackets = [[NSMutableArray alloc] init]; _running = YES; - [self startAudioThread]; + // [self start]; } - (void)audioThreadEntry @@ -249,13 +289,13 @@ - (void)submitPacket:(AVPacket *)packet } } -- (void)startAudioThread +- (void)start { _audioThread = [[NSThread alloc] initWithTarget:self selector:@selector(audioThreadEntry) object:nil]; [_audioThread start]; } -- (void)stopAudioThread +- (void)stop { _running = NO; [_audioThread cancel]; @@ -272,28 +312,6 @@ - (void)setVolume:(float)volume _volume = volume; } -- (void)dealloc -{ - [self stopAudioThread]; - - if (_audioFrame) - av_frame_free(&_audioFrame); - - if (_audioCodecCtx) - avcodec_free_context(&_audioCodecCtx); - - if (_swrCtx) - swr_free(&_swrCtx); - - if (_aoDev) - ao_close(_aoDev); - - RELEASE(_audioPackets); - - ao_shutdown(); - [super dealloc]; -} - @end @implementation GSMovieView @@ -317,7 +335,6 @@ - (instancetype) initWithFrame: (NSRect)frame return self; } - - (void)dealloc { [self stop: nil]; @@ -331,53 +348,56 @@ - (void)dealloc DESTROY(_videoPackets); // DESTROY(_currentFrame); - // DESTROY(_audioPlayer); + DESTROY(_audioPlayer); [super dealloc]; } -/* -- (void)logStreamMetadata -{ - double duration = (double)_formatContext->duration / AV_TIME_BASE; - NSString *info = [NSString stringWithFormat:@"Video: %dx%d %@ %.2fs", - _codecContext->width, - _codecContext->height, - [NSString stringWithUTF8String:avcodec_get_name(_codecContext->codec_id)], - duration]; - - if (_audioStreamIndex != -1) - { - AVCodecParameters *ap = _formatContext->streams[_audioStreamIndex]->codecpar; - NSString *audioInfo = [NSString stringWithFormat: @"Audio codec: %s, sample rate: %d", - avcodec_get_name(ap->codec_id), - ap->sample_rate]; - info = [NSString stringWithFormat: @"%@ %@", info, audioInfo]; - } - - NSLog(@"%@", info); -} -*/ - -- (void) updateImage: (NSImage *)image +// Overridden methods from the superclass... +- (BOOL) isPlaying { - ASSIGN(_currentFrame, image); - [self setNeedsDisplay:YES]; + return _running; } - (IBAction) start: (id)sender { + [self setRate: 1.0 / 30.0]; + [self setVolume: 1.0]; + _feedThread = RETAIN([[NSThread alloc] initWithTarget:self selector:@selector(feed) object:nil]); [_feedThread start]; + [_audioPlayer start]; } - (IBAction) stop: (id)sender { [_feedThread cancel]; [self stop]; + [_audioPlayer stop]; + DESTROY(_feedThread); } +- (void) setVolume: (float)volume +{ + [super setVolume: volume]; + [_audioPlayer setVolume: volume]; +} + +- (NSRect) movieRect +{ + return NSMakeRect(0.0, 0.0, + (float)_videoCodecCtx->width, + (float)_videoCodecCtx->height); +} + +// Video playback methods... +- (void) updateImage: (NSImage *)image +{ + ASSIGN(_currentFrame, image); + [self setNeedsDisplay:YES]; +} + - (void) drawRect: (NSRect)dirtyRect { [super drawRect: dirtyRect]; @@ -448,19 +468,18 @@ - (void) feed int64_t i = 0; while (av_read_frame(formatCtx, &packet) >= 0) { - // After 100 frames, start the thread... + // After 1000 frames, start the thread... if (i == 1000) { [self start]; } if (packet.stream_index == videoStream) - [self submitVideoPacket:&packet]; + [self submitVideoPacket: &packet]; - /* if (packet.stream_index == audioStream) - [_audioPlayer submitVideoPacket:&packet]; - */ + [_audioPlayer submitPacket: &packet]; + av_packet_unref(&packet); i++; } @@ -640,187 +659,4 @@ - (void)decodeVideoPacket:(AVPacket *)packet } } -/* -- (void) prepareDecoder -{ - NSString *moviePath = [[_movie URL] path]; - - _formatContext = avformat_alloc_context(); - if (avformat_open_input(&_formatContext, [moviePath UTF8String], NULL, NULL) != 0) return; - if (avformat_find_stream_info(_formatContext, NULL) < 0) return; - - _videoStreamIndex = -1; - _audioStreamIndex = -1; - for (int i = 0; i < _formatContext->nb_streams; i++) - { - if (_formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO - && _videoStreamIndex == -1) - { - _videoStreamIndex = i; - } - else if (_formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO - && _audioStreamIndex == -1) - { - _audioStreamIndex = i; - } - } - - if (_videoStreamIndex == -1) return; - if (_audioStreamIndex != -1) - { - [_audioPlayer setVolume: [super volume]]; - [_audioPlayer prepareAudioWithFormatContext: _formatContext - streamIndex: _audioStreamIndex]; - } - - AVCodecParameters *codecPar = _formatContext->streams[_videoStreamIndex]->codecpar; - const AVCodec *codec = avcodec_find_decoder(codecPar->codec_id); - - _videoTimeBase = _formatContext->streams[_videoStreamIndex]->time_base; - _codecContext = avcodec_alloc_context3(codec); - avcodec_parameters_to_context(_codecContext, codecPar); - if (avcodec_open2(_codecContext, codec, NULL) < 0) return; - - _avframe = av_frame_alloc(); - _avframeRGB = av_frame_alloc(); - - int numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, _codecContext->width, _codecContext->height, 1); - _buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t)); - av_image_fill_arrays(_avframeRGB->data, _avframeRGB->linesize, _buffer, AV_PIX_FMT_RGB24, - _codecContext->width, _codecContext->height, 1); - - _swsCtx = sws_getContext(_codecContext->width, _codecContext->height, _codecContext->pix_fmt, - _codecContext->width, _codecContext->height, AV_PIX_FMT_RGB24, - SWS_BILINEAR, NULL, NULL, NULL); - - [self logStreamMetadata]; -} - -- (void) decodeAndDisplayNextFrame -{ - AVPacket *packet = av_packet_alloc(); - packet->data = NULL; - packet->size = 0; - - while (av_read_frame(_formatContext, packet) >= 0) - { - if (!_playing) break; - - if (packet->stream_index == _videoStreamIndex) - { - avcodec_send_packet(_codecContext, packet); - if (avcodec_receive_frame(_codecContext, _avframe) == 0) - { - sws_scale(_swsCtx, (const uint8_t * const *)_avframe->data, _avframe->linesize, 0, - _codecContext->height, _avframeRGB->data, _avframeRGB->linesize); - - NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] - initWithBitmapDataPlanes: _avframeRGB->data - pixelsWide: _codecContext->width - pixelsHigh: _codecContext->height - bitsPerSample: 8 - samplesPerPixel: 3 - hasAlpha: NO - isPlanar: NO - colorSpaceName: NSCalibratedRGBColorSpace - bytesPerRow: _avframeRGB->linesize[0] - bitsPerPixel: 24]; - NSSize imageSize = NSMakeSize(_codecContext->width, _codecContext->height); - NSImage *image = [[NSImage alloc] initWithSize: imageSize]; - - [image addRepresentation:rep]; - [self performSelectorOnMainThread: @selector(updateImage:) - withObject: image - waitUntilDone: NO]; - AUTORELEASE(rep); - - break; - } - } - else if (packet->stream_index == _audioStreamIndex) - { - [_audioPlayer submitPacket: packet]; - } - av_packet_unref(packet); - } -} - - -- (void) start: (id)sender -{ - [super start: sender]; - [self setRate: 1.0 / 30.0]; - [self setVolume: 1.0]; - - _decodeTimer = - [NSTimer scheduledTimerWithTimeInterval: [self rate] - target: self - selector: @selector(decodeAndDisplayNextFrame) - userInfo: nil - repeats: YES]; -} - -- (void) stop: (id)sender -{ - [super stop: sender]; - - if (_decodeTimer) - { - [_decodeTimer invalidate]; - RELEASE(_decodeTimer); - _decodeTimer = nil; - } - - if (_avframe) - { - av_frame_free(&_avframe); - _avframe = NULL; - } - - if (_avframeRGB) - { - av_frame_free(&_avframeRGB); - _avframeRGB = NULL; - } - - if (_buffer) - { - av_free(_buffer); - _buffer = NULL; - } - - if (_codecContext) - { - avcodec_free_context(&_codecContext); - _codecContext = NULL; - } - - if (_formatContext) - { - avformat_close_input(&_formatContext); - _formatContext = NULL; - } - - if (_swsCtx) - { - sws_freeContext(_swsCtx); - _swsCtx = NULL; - } -} - -- (void) setVolume: (float)volume -{ - [super setVolume: volume]; - [_audioPlayer setVolume: volume]; -} - -- (NSRect) movieRect -{ - return NSMakeRect(0.0, 0.0, - (float)_codecContext->width, - (float)_codecContext->height); -} - -*/ - @end From 5b3afb89df1c34d35ed15411ba2dc6ab91d3548d Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Thu, 29 May 2025 15:22:32 -0400 Subject: [PATCH 24/86] Rename Audio class, initialize it in the code if there is an audio stream --- Source/GSMovieView.h | 10 +++---- Source/GSMovieView.m | 66 ++++++++++++++++++++++++-------------------- 2 files changed, 41 insertions(+), 35 deletions(-) diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index 17b6051a14..8d564c4f14 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -45,7 +45,7 @@ @class NSImage; @class NSTimer; -@class FFmpegAudioPlayer; +@class GSAudioPlayer; APPKIT_EXPORT_CLASS @interface GSMovieView : NSMovieView @@ -54,7 +54,7 @@ APPKIT_EXPORT_CLASS NSThread *_videoThread; NSThread *_feedThread; NSImage *_currentFrame; - FFmpegAudioPlayer *_audioPlayer; + GSAudioPlayer *_audioPlayer; AVCodecContext *_videoCodecCtx; AVFrame *_videoFrame; @@ -70,9 +70,9 @@ APPKIT_EXPORT_CLASS streamIndex: (int)videoStreamIndex; - (void) submitVideoPacket: (AVPacket *)packet; - (void) decodeVideoPacket: (AVPacket *)packet; -- (void) start; -- (void) stop; -- (void) feed; +- (void) startVideo; +- (void) stopVideo; +- (void) feedVideo; // - (void) logStreamMetadata; @end diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index cc3d9e56ff..1a88cd36c1 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -78,7 +78,7 @@ static AVPacket AVPacketFromNSDictionary(NSDictionary *dict) return *packet; } -@interface FFmpegAudioPlayer : NSObject +@interface GSAudioPlayer : NSObject { AVCodecContext *_audioCodecCtx; AVFrame *_audioFrame; @@ -98,13 +98,13 @@ @interface FFmpegAudioPlayer : NSObject - (void) prepareAudioWithFormatContext:(AVFormatContext *)formatCtx streamIndex:(int)audioStreamIndex; - (void) decodeAudioPacket:(AVPacket *)packet; -- (void) start; -- (void) stop; +- (void) startAudio; +- (void) stopAudio; - (void) setVolume: (float)volume; @end -@implementation FFmpegAudioPlayer +@implementation GSAudioPlayer - (instancetype) init { self = [super init]; @@ -126,7 +126,7 @@ - (instancetype) init - (void)dealloc { - [self stop]; + [self stopAudio]; if (_audioFrame) av_frame_free(&_audioFrame); @@ -196,7 +196,6 @@ - (void) prepareAudioWithFormatContext:(AVFormatContext *)formatCtx _audioClock = av_gettime(); _audioPackets = [[NSMutableArray alloc] init]; _running = YES; - // [self start]; } - (void)audioThreadEntry @@ -285,17 +284,17 @@ - (void)submitPacket:(AVPacket *)packet NSDictionary *dict = NSDictionaryFromAVPacket(packet); @synchronized (_audioPackets) { - [_audioPackets addObject:dict]; + [_audioPackets addObject: dict]; } } -- (void)start +- (void)startAudio { _audioThread = [[NSThread alloc] initWithTarget:self selector:@selector(audioThreadEntry) object:nil]; [_audioThread start]; } -- (void)stop +- (void)stopAudio { _running = NO; [_audioThread cancel]; @@ -305,7 +304,7 @@ - (void)stop _audioThread = nil; } -- (void)setVolume:(float)volume +- (void) setVolume: (float)volume { if (volume < 0.0) volume = 0.0; if (volume > 1.0) volume = 1.0; @@ -324,7 +323,7 @@ - (instancetype) initWithFrame: (NSRect)frame _currentFrame = nil; _videoThread = nil; _feedThread = nil; - _audioPlayer = [[FFmpegAudioPlayer alloc] init]; + _audioPlayer = [[GSAudioPlayer alloc] init]; _videoPackets = RETAIN([[NSMutableArray alloc] init]); _running = NO; _started = NO; @@ -364,16 +363,16 @@ - (IBAction) start: (id)sender [self setRate: 1.0 / 30.0]; [self setVolume: 1.0]; - _feedThread = RETAIN([[NSThread alloc] initWithTarget:self selector:@selector(feed) object:nil]); + _feedThread = RETAIN([[NSThread alloc] initWithTarget:self selector:@selector(feedVideo) object:nil]); [_feedThread start]; - [_audioPlayer start]; + [_audioPlayer startAudio]; } - (IBAction) stop: (id)sender { [_feedThread cancel]; - [self stop]; - [_audioPlayer stop]; + [self stopVideo]; + [_audioPlayer stopAudio]; DESTROY(_feedThread); } @@ -392,6 +391,7 @@ - (NSRect) movieRect } // Video playback methods... + - (void) updateImage: (NSImage *)image { ASSIGN(_currentFrame, image); @@ -407,7 +407,7 @@ - (void) drawRect: (NSRect)dirtyRect } } -- (void) feed +- (void) feedVideo { NSMovie *movie = [self movie]; NSURL *url = [movie URL]; @@ -456,13 +456,17 @@ - (void) feed return; } - // If it's video only we just log it and continue... - if (audioStream == -1) + [self prepareVideoWithFormatContext: formatCtx + streamIndex: videoStream]; + if (audioStream == -1) // if we do have an audio stream, initialize it... otherwise log it { - NSLog(@"[Error] No audio stream found. | Timestamp: %ld", av_gettime()); + NSLog(@"[Info] No audio stream found. | Timestamp: %ld", av_gettime()); + } + else + { + [_audioPlayer prepareAudioWithFormatContext: formatCtx + streamIndex: videoStream]; } - - [self prepareVideoWithFormatContext:formatCtx streamIndex:videoStream]; AVPacket packet; int64_t i = 0; @@ -471,7 +475,7 @@ - (void) feed // After 1000 frames, start the thread... if (i == 1000) { - [self start]; + [self startVideo]; } if (packet.stream_index == videoStream) @@ -488,7 +492,7 @@ - (void) feed if (i < 1000) { NSLog(@"[GSMovieView] Starting short video... | Timestamp: %ld", av_gettime()); - [self start]; + [self startVideo]; } avformat_close_input(&formatCtx); @@ -524,7 +528,7 @@ - (void)prepareVideoWithFormatContext:(AVFormatContext *)formatCtx streamIndex:( _started = NO; } -- (void) start +- (void) startVideo { NSLog(@"[GSMovieView] Starting video thread | Timestamp: %ld", av_gettime()); if (!_running) @@ -535,7 +539,7 @@ - (void) start } } -- (void) stop +- (void) stopVideo { NSLog(@"[GSMovieView] Stopping video thread | Timestamp: %ld", av_gettime()); if (_running) @@ -553,7 +557,7 @@ - (void)submitVideoPacket:(AVPacket *)packet NSDictionary *dict = NSDictionaryFromAVPacket(packet); @synchronized (_videoPackets) { - [_videoPackets addObject:dict]; + [_videoPackets addObject: dict]; } } @@ -588,15 +592,17 @@ - (void)videoThreadEntry if (dict) { - // NSLog(@"[GSMovieView] Rendering frame PTS: %ld | Delay: %ld us", packet.pts, delay); AVPacket packet = AVPacketFromNSDictionary(dict); - int64_t packetTime = av_rescale_q(packet.pts, _timeBase, (AVRational){1, 1000000}); int64_t now = av_gettime() - _videoClock; int64_t delay = packetTime - now; + + fprintf(stderr, "[GSMovieView] Rendering video frame PTS: %ld | Delay: %ld us\r", packet.pts, delay); if (delay > 0) - usleep((useconds_t)delay); - + { + usleep((useconds_t)delay); + } + [self decodeVideoPacket:&packet]; RELEASE(dict); } From dd02d4f1fa73bf9c6cb2abb14913f8f2057edc9a Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Thu, 29 May 2025 15:34:17 -0400 Subject: [PATCH 25/86] Re-integrate audio --- Source/GSMovieView.m | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 1a88cd36c1..a3d13bddfd 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -465,7 +465,7 @@ - (void) feedVideo else { [_audioPlayer prepareAudioWithFormatContext: formatCtx - streamIndex: videoStream]; + streamIndex: audioStream]; } AVPacket packet; @@ -476,6 +476,7 @@ - (void) feedVideo if (i == 1000) { [self startVideo]; + [_audioPlayer startAudio]; } if (packet.stream_index == videoStream) @@ -493,6 +494,7 @@ - (void) feedVideo { NSLog(@"[GSMovieView] Starting short video... | Timestamp: %ld", av_gettime()); [self startVideo]; + [_audioPlayer startAudio]; } avformat_close_input(&formatCtx); @@ -574,7 +576,7 @@ - (void)videoThreadEntry if (!_started && [_videoPackets count] < 3) { usleep(5000); - [pool release]; + RELEASE(pool); continue; } if ([_videoPackets count] > 0) @@ -603,7 +605,7 @@ - (void)videoThreadEntry usleep((useconds_t)delay); } - [self decodeVideoPacket:&packet]; + [self decodeVideoPacket: &packet]; RELEASE(dict); } else From 61bd0c89643ae136fcf32a4775bd4f6cc3ff56b9 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Thu, 29 May 2025 15:55:15 -0400 Subject: [PATCH 26/86] Add logging when sound stream is found --- Source/GSMovieView.m | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index a3d13bddfd..a1ebd95023 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -290,6 +290,7 @@ - (void)submitPacket:(AVPacket *)packet - (void)startAudio { + NSLog(@"[GSMovieView] Starting audio thread | Timestamp: %ld", av_gettime()); _audioThread = [[NSThread alloc] initWithTarget:self selector:@selector(audioThreadEntry) object:nil]; [_audioThread start]; } From 4b9e6c371987266b1031e359b7734a377b1a3fe1 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Thu, 29 May 2025 23:32:50 -0400 Subject: [PATCH 27/86] Add other methods --- Source/GSMovieView.m | 72 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index a1ebd95023..4f95f4f3da 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -347,7 +347,7 @@ - (void)dealloc sws_freeContext(_swsCtx); DESTROY(_videoPackets); - // DESTROY(_currentFrame); + TEST_RELEASE(_currentFrame); DESTROY(_audioPlayer); [super dealloc]; @@ -391,6 +391,76 @@ - (NSRect) movieRect (float)_videoCodecCtx->height); } +- (IBAction)gotoPosterFrame:(id)sender +{ + NSLog(@"[GSMovieView] gotoPosterFrame called | Timestamp: %ld", av_gettime()); + // Reset to first video frame + [self stop: sender]; + [self start: sender]; +} + +- (IBAction)gotoBeginning:(id)sender +{ + NSLog(@"[GSMovieView] gotoBeginning called | Timestamp: %ld", av_gettime()); + [self gotoPosterFrame: sender]; +} + +- (IBAction)gotoEnd:(id)sender +{ + NSURL *url = [[self movie] URL]; + NSString *path = [url path]; + + NSLog(@"[GSMovieView] gotoEnd called | Timestamp: %ld", av_gettime()); + + // Seek to the end of the video stream + [self stop: sender]; + + AVFormatContext *formatCtx = NULL; + if (avformat_open_input(&formatCtx, [path UTF8String], NULL, NULL) != 0) + { + return; + } + + if (avformat_find_stream_info(formatCtx, NULL) < 0) + { + avformat_close_input(&formatCtx); + return; + } + + int videoStream = -1; + for (unsigned int i = 0; i < formatCtx->nb_streams; ++i) + { + if (formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) + { + videoStream = i; + break; + } + } + + if (videoStream == -1) + { + avformat_close_input(&formatCtx); + return; + } + + int64_t duration = formatCtx->streams[videoStream]->duration; + // AVRational timeBase = formatCtx->streams[videoStream]->time_base; + + int64_t seekTarget = duration - AV_TIME_BASE; + av_seek_frame(formatCtx, videoStream, seekTarget, AVSEEK_FLAG_BACKWARD); + + [self feedVideo]; + avformat_close_input(&formatCtx); +} + +- (void) stepForward: (id)sender +{ +} + +- (void) stepBack: (id)sender +{ +} + // Video playback methods... - (void) updateImage: (NSImage *)image From a2e54de1a99bcf98769a4852f5b940df6aff86de Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Thu, 29 May 2025 23:37:54 -0400 Subject: [PATCH 28/86] Update actions, add implementation for some actions --- ChangeLog | 17 +++++++++++++++++ Headers/AppKit/NSMovieView.h | 26 +++++++++++++------------- Source/GSMovieView.m | 4 ++-- Source/NSMovieView.m | 26 +++++++++++++------------- 4 files changed, 45 insertions(+), 28 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9d93a22cc4..45620274d6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2025-05-29 Gregory John Casamento + + * config.make.in + * configure + * configure.ac + * Headers/Additions/GNUstepGUI/config.h.in + * Headers/AppKit/NSMovie.h + * Headers/AppKit/NSMovieView.h + * Source/GNUmakefile + * Source/GNUmakefile.preamble + * Source/GSMovieView.h + * Source/GSMovieView.m + * Source/NSMovie.m + * Source/NSMovieView.m + * Source/NSSound.m: Cleanup NSSound, add support for playing ffmpeg + movies using NSMovie, NSMovieView. + 2025-04-30 Gregory John Casamento * Headers/AppKit/NSColorSpace.h: Add NSColorSpaceModel* enumerated values. diff --git a/Headers/AppKit/NSMovieView.h b/Headers/AppKit/NSMovieView.h index c61615909a..f4b6f5fcf1 100644 --- a/Headers/AppKit/NSMovieView.h +++ b/Headers/AppKit/NSMovieView.h @@ -73,12 +73,12 @@ APPKIT_EXPORT_CLASS /** * Start movie playback. */ -- (void) start: (id)sender; +- (IBAction) start: (id)sender; /** * Stop movie playback. */ -- (void) stop: (id)sender; +- (IBAction) stop: (id)sender; /** * Check whether the movie is currently playing. @@ -88,27 +88,27 @@ APPKIT_EXPORT_CLASS /** * Go to the movie's poster frame. */ -- (void) gotoPosterFrame: (id)sender; +- (IBAction) gotoPosterFrame: (id)sender; /** * Move to the beginning of the movie. */ -- (void) gotoBeginning: (id)sender; +- (IBAction) gotoBeginning: (id)sender; /** * Move to the end of the movie. */ -- (void) gotoEnd: (id)sender; +- (IBAction) gotoEnd: (id)sender; /** * Step forward one frame in the movie. */ -- (void) stepForward: (id)sender; +- (IBAction) stepForward: (id)sender; /** * Step backward one frame in the movie. */ -- (void) stepBack: (id)sender; +- (IBAction) stepBack: (id)sender; /** * Set the playback rate for the movie. @@ -213,32 +213,32 @@ APPKIT_EXPORT_CLASS /** * Cut the selected movie content. */ -- (void) cut: (id)sender; +- (IBAction) cut: (id)sender; /** * Copy the selected movie content. */ -- (void) copy: (id)sender; +- (IBAction) copy: (id)sender; /** * Paste movie content from the pasteboard. */ -- (void) paste: (id)sender; +- (IBAction) paste: (id)sender; /** * Clear the selected movie content. */ -- (void) clear: (id)sender; +- (IBAction) clear: (id)sender; /** * Undo the last operation. */ -- (void) undo: (id)sender; +- (IBAction) undo: (id)sender; /** * Select all content in the movie view. */ -- (void) selectAll: (id)sender; +- (IBAction) selectAll: (id)sender; @end diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 4f95f4f3da..3087fe2e43 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -453,11 +453,11 @@ - (IBAction)gotoEnd:(id)sender avformat_close_input(&formatCtx); } -- (void) stepForward: (id)sender +- (IBAction) stepForward: (id)sender { } -- (void) stepBack: (id)sender +- (IBAction) stepBack: (id)sender { } diff --git a/Source/NSMovieView.m b/Source/NSMovieView.m index a808af6794..8aa53cbae1 100644 --- a/Source/NSMovieView.m +++ b/Source/NSMovieView.m @@ -88,11 +88,11 @@ - (NSMovie*) movie return _movie; } -- (void) start: (id)sender +- (IBAction) start: (id)sender { } -- (void) stop: (id)sender +- (IBAction) stop: (id)sender { } @@ -101,23 +101,23 @@ - (BOOL) isPlaying return NO; } -- (void) gotoPosterFrame: (id)sender +- (IBAction) gotoPosterFrame: (id)sender { } -- (void) gotoBeginning: (id)sender +- (IBAction) gotoBeginning: (id)sender { } -- (void) gotoEnd: (id)sender +- (IBAction) gotoEnd: (id)sender { } -- (void) stepForward: (id)sender +- (IBAction) stepForward: (id)sender { } -- (void) stepBack: (id)sender +- (IBAction) stepBack: (id)sender { } @@ -220,27 +220,27 @@ - (BOOL) isEditable return _flags.editable; } -- (void) cut: (id)sender +- (IBAction) cut: (id)sender { } -- (void) copy: (id)sender +- (IBAction) copy: (id)sender { } -- (void) paste: (id)sender +- (IBAction) paste: (id)sender { } -- (void) clear: (id)sender +- (IBAction) clear: (id)sender { } -- (void) undo: (id)sender +- (IBAction) undo: (id)sender { } -- (void) selectAll: (id)sender +- (IBAction) selectAll: (id)sender { } From ad69f777adc4dd66e97a05445e7d2b161bd44558 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Fri, 30 May 2025 00:25:30 -0400 Subject: [PATCH 29/86] Add proper declaration --- Headers/AppKit/NSMovieView.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Headers/AppKit/NSMovieView.h b/Headers/AppKit/NSMovieView.h index f4b6f5fcf1..471463e37d 100644 --- a/Headers/AppKit/NSMovieView.h +++ b/Headers/AppKit/NSMovieView.h @@ -32,6 +32,7 @@ #define _GNUstep_H_NSMovieView #import +#import #import @class NSMovie; From 1150ab00c410eea4e5e52505d0620761dc20fbb7 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Fri, 30 May 2025 17:54:53 -0400 Subject: [PATCH 30/86] Add code to return list of supported video types --- Source/GSMovieView.h | 5 +++-- Source/GSMovieView.m | 34 ++++++++++++++++++++++++++++++++++ Source/NSMovie.m | 2 +- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index 8d564c4f14..bfa0ec7a81 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -38,10 +38,11 @@ /* FFmpeg headers */ #include #include -#include -#include +#include #include #include +#include +#include @class NSImage; @class NSTimer; diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 3087fe2e43..de19a8e54e 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -78,6 +78,39 @@ static AVPacket AVPacketFromNSDictionary(NSDictionary *dict) return *packet; } +// Ignore the warning this will produce as it is intentional. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation" + +// Category smash this method to get the proper types. +@interface NSMovie (AVCodec) +@end + +@implementation NSMovie (AVCodec) + ++ (NSArray*) movieUnfilteredFileTypes +{ + NSMutableArray *result = [NSMutableArray array]; + const AVCodec *codec = NULL; + void *i = 0; + + printf("Available codecs:\n"); + while ((codec = av_codec_iterate(&i))) + { + if (av_codec_is_decoder(codec) && codec->type == AVMEDIA_TYPE_VIDEO) + { + [result addObject: [NSString stringWithUTF8String: codec->name]]; + } + } + + return result; +} + +@end + +#pragma clang diagnostic pop + +// Audio player for NSMovieView... @interface GSAudioPlayer : NSObject { AVCodecContext *_audioCodecCtx; @@ -314,6 +347,7 @@ - (void) setVolume: (float)volume @end +// NSMovieView subclass that does all of the actual work of decoding... @implementation GSMovieView - (instancetype) initWithFrame: (NSRect)frame diff --git a/Source/NSMovie.m b/Source/NSMovie.m index d12d342e36..ed1aeb2841 100644 --- a/Source/NSMovie.m +++ b/Source/NSMovie.m @@ -58,7 +58,7 @@ @implementation NSMovie + (NSArray*) movieUnfilteredFileTypes { - return [NSArray arrayWithObjects: @"mp4", @"mov", @"avi", @"flv", @"mkv", @"webm", nil ]; + return [NSArray array]; // WithObjects: @"mp4", @"mov", @"avi", @"flv", @"mkv", @"webm", nil ]; } + (NSArray*) movieUnfilteredPasteboardTypes From 8392360663d47164187373f357eb7425c92e660c Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Fri, 30 May 2025 23:23:43 -0400 Subject: [PATCH 31/86] Add audio buffer using NSData --- Source/GSMovieView.m | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index de19a8e54e..9c88481a75 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -121,11 +121,13 @@ @interface GSAudioPlayer : NSObject int64_t _lastPTS; int64_t _audioClock; AVRational _timeBase; - NSMutableArray *_audioPackets; - NSThread *_audioThread; BOOL _running; float _volume; /* 0.0 to 1.0 */ BOOL _started; + + NSMutableArray *_audioPackets; + NSThread *_audioThread; + NSData *_audioBuffer; } - (void) prepareAudioWithFormatContext:(AVFormatContext *)formatCtx @@ -228,6 +230,7 @@ - (void) prepareAudioWithFormatContext:(AVFormatContext *)formatCtx _lastPTS = 0; _audioClock = av_gettime(); _audioPackets = [[NSMutableArray alloc] init]; + _audioBuffer = [[NSMutableData alloc] init]; _running = YES; } From 9a7ac689b8c036b78064412eb1be9aee10cfeed2 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Sat, 31 May 2025 14:03:27 -0400 Subject: [PATCH 32/86] Add pasteboard types, clean up NSMovie --- Source/GSMovieView.m | 23 ++++++++++++++++++++++- Source/NSMovie.m | 4 ++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 9c88481a75..719d832792 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -89,12 +89,33 @@ @interface NSMovie (AVCodec) @implementation NSMovie (AVCodec) + (NSArray*) movieUnfilteredFileTypes +{ + NSMutableSet *extensionsSet = [NSMutableSet set]; + void *opaque = NULL; + const AVOutputFormat *ofmt = NULL; + + // Iterate over all muxers + while ((ofmt = av_muxer_iterate(&opaque))) + { + if (ofmt->extensions) + { + NSString *extString = [NSString stringWithUTF8String:ofmt->extensions]; + NSArray *exts = [extString componentsSeparatedByString:@","]; + [extensionsSet addObjectsFromArray:exts]; + } + } + + // Convert to sorted array + NSArray *sortedExtensions = [[extensionsSet allObjects] sortedArrayUsingSelector:@selector(compare:)]; + return sortedExtensions; +} + ++ (NSArray*) movieUnfilteredPasteboardTypes { NSMutableArray *result = [NSMutableArray array]; const AVCodec *codec = NULL; void *i = 0; - printf("Available codecs:\n"); while ((codec = av_codec_iterate(&i))) { if (av_codec_is_decoder(codec) && codec->type == AVMEDIA_TYPE_VIDEO) diff --git a/Source/NSMovie.m b/Source/NSMovie.m index ed1aeb2841..5eeac64902 100644 --- a/Source/NSMovie.m +++ b/Source/NSMovie.m @@ -58,12 +58,12 @@ @implementation NSMovie + (NSArray*) movieUnfilteredFileTypes { - return [NSArray array]; // WithObjects: @"mp4", @"mov", @"avi", @"flv", @"mkv", @"webm", nil ]; + return [NSArray array]; } + (NSArray*) movieUnfilteredPasteboardTypes { - return [self movieUnfilteredFileTypes]; + return [NSArray array]; } + (BOOL) canInitWithPasteboard: (NSPasteboard*)pasteboard From f87e26116e0c305f97b28b459bbb1223bc360747 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Sat, 31 May 2025 14:56:26 -0400 Subject: [PATCH 33/86] Add ring buffer class --- Source/GSMovieView.m | 116 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 719d832792..3d0b339b93 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -131,6 +131,120 @@ + (NSArray*) movieUnfilteredPasteboardTypes #pragma clang diagnostic pop +#define AUDIO_RING_SIZE 128 + +@interface PacketRingBuffer : NSObject +{ + NSMutableArray *_buffer; + NSInteger _head; + NSInteger _tail; + NSInteger _count; + NSLock *_lock; +} + +- (instancetype) init; +- (BOOL) push:(NSDictionary *) packet; +- (NSDictionary *) pop; +- (NSInteger) count; +- (void) clear; + +@end + +@implementation PacketRingBuffer + +- (instancetype) init +{ + if ((self = [super init])) + { + _buffer = [[NSMutableArray alloc] initWithCapacity:AUDIO_RING_SIZE]; + for (int i = 0; i < AUDIO_RING_SIZE; i++) + { + [_buffer addObject:[NSNull null]]; + } + _head = 0; + _tail = 0; + _count = 0; + _lock = [[NSLock alloc] init]; + } + return self; +} + +- (BOOL) push:(NSDictionary *)packet +{ + [_lock lock]; + + if (_count >= AUDIO_RING_SIZE) + { + [_lock unlock]; + return NO; + } + + RETAIN(packet); + [_buffer replaceObjectAtIndex:_tail withObject: packet]; + _tail = (_tail + 1) % AUDIO_RING_SIZE; + _count++; + [_lock unlock]; + + return YES; +} + +- (NSDictionary *)pop +{ + [_lock lock]; + if (_count == 0) { + [_lock unlock]; + return nil; + } + + NSDictionary *pkt = RETAIN([_buffer objectAtIndex:_head]); + + [_buffer replaceObjectAtIndex:_head withObject:[NSNull null]]; + _head = (_head + 1) % AUDIO_RING_SIZE; + _count--; + [_lock unlock]; + + return AUTORELEASE(pkt); +} + +- (NSInteger) count +{ + [_lock lock]; + NSInteger c = _count; + [_lock unlock]; + + return c; +} + +- (void) clear +{ + [_lock lock]; + + for (int i = 0; i < AUDIO_RING_SIZE; i++) + { + id obj = [_buffer objectAtIndex:i]; + if (![obj isKindOfClass:[NSNull class]]) + { + RELEASE(obj); + [_buffer replaceObjectAtIndex:i withObject:[NSNull null]]; + } + } + + _head = 0; + _tail = 0; + _count = 0; + [_lock unlock]; +} + +- (void) dealloc +{ + [self clear]; + RELEASE(_buffer); + RELEASE(_lock); + [super dealloc]; +} + +@end + // Audio player for NSMovieView... @interface GSAudioPlayer : NSObject { @@ -149,6 +263,7 @@ @interface GSAudioPlayer : NSObject NSMutableArray *_audioPackets; NSThread *_audioThread; NSData *_audioBuffer; + PacketRingBuffer *_ring; } - (void) prepareAudioWithFormatContext:(AVFormatContext *)formatCtx @@ -218,6 +333,7 @@ - (void) prepareAudioWithFormatContext:(AVFormatContext *)formatCtx return; } + _ring = [[PacketRingBuffer alloc] init]; _audioCodecCtx = avcodec_alloc_context3(audioCodec); avcodec_parameters_to_context(_audioCodecCtx, audioPar); From 36b841451d008fef66136b8402419522869545cc Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Tue, 3 Jun 2025 00:36:50 -0400 Subject: [PATCH 34/86] Make sure swr_init is checked to see if it returns 0 --- Source/GSMovieView.m | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 3d0b339b93..35babebfb3 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -354,8 +354,12 @@ - (void) prepareAudioWithFormatContext:(AVFormatContext *)formatCtx _audioCodecCtx->sample_fmt, _audioCodecCtx->sample_rate, 0, NULL); - swr_init(_swrCtx); - + int r = swr_init(_swrCtx); + if (r == 0) + { + NSLog(@"[GSMovieView] WARNING: swr_init returned 0"); + } + memset(&_aoFmt, 0, sizeof(ao_sample_format)); _aoFmt.bits = 16; _aoFmt.channels = out_channels; From fbf447aa100d7aed8db342276b6e63bb6e54bee5 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Tue, 3 Jun 2025 02:06:09 -0400 Subject: [PATCH 35/86] Remove ring buffer --- Source/GSMovieView.m | 118 ------------------------------------------- 1 file changed, 118 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 35babebfb3..403eccecda 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -131,120 +131,6 @@ + (NSArray*) movieUnfilteredPasteboardTypes #pragma clang diagnostic pop -#define AUDIO_RING_SIZE 128 - -@interface PacketRingBuffer : NSObject -{ - NSMutableArray *_buffer; - NSInteger _head; - NSInteger _tail; - NSInteger _count; - NSLock *_lock; -} - -- (instancetype) init; -- (BOOL) push:(NSDictionary *) packet; -- (NSDictionary *) pop; -- (NSInteger) count; -- (void) clear; - -@end - -@implementation PacketRingBuffer - -- (instancetype) init -{ - if ((self = [super init])) - { - _buffer = [[NSMutableArray alloc] initWithCapacity:AUDIO_RING_SIZE]; - for (int i = 0; i < AUDIO_RING_SIZE; i++) - { - [_buffer addObject:[NSNull null]]; - } - _head = 0; - _tail = 0; - _count = 0; - _lock = [[NSLock alloc] init]; - } - return self; -} - -- (BOOL) push:(NSDictionary *)packet -{ - [_lock lock]; - - if (_count >= AUDIO_RING_SIZE) - { - [_lock unlock]; - return NO; - } - - RETAIN(packet); - [_buffer replaceObjectAtIndex:_tail withObject: packet]; - _tail = (_tail + 1) % AUDIO_RING_SIZE; - _count++; - [_lock unlock]; - - return YES; -} - -- (NSDictionary *)pop -{ - [_lock lock]; - if (_count == 0) { - [_lock unlock]; - return nil; - } - - NSDictionary *pkt = RETAIN([_buffer objectAtIndex:_head]); - - [_buffer replaceObjectAtIndex:_head withObject:[NSNull null]]; - _head = (_head + 1) % AUDIO_RING_SIZE; - _count--; - [_lock unlock]; - - return AUTORELEASE(pkt); -} - -- (NSInteger) count -{ - [_lock lock]; - NSInteger c = _count; - [_lock unlock]; - - return c; -} - -- (void) clear -{ - [_lock lock]; - - for (int i = 0; i < AUDIO_RING_SIZE; i++) - { - id obj = [_buffer objectAtIndex:i]; - if (![obj isKindOfClass:[NSNull class]]) - { - RELEASE(obj); - [_buffer replaceObjectAtIndex:i withObject:[NSNull null]]; - } - } - - _head = 0; - _tail = 0; - _count = 0; - [_lock unlock]; -} - -- (void) dealloc -{ - [self clear]; - RELEASE(_buffer); - RELEASE(_lock); - [super dealloc]; -} - -@end - // Audio player for NSMovieView... @interface GSAudioPlayer : NSObject { @@ -262,8 +148,6 @@ @interface GSAudioPlayer : NSObject NSMutableArray *_audioPackets; NSThread *_audioThread; - NSData *_audioBuffer; - PacketRingBuffer *_ring; } - (void) prepareAudioWithFormatContext:(AVFormatContext *)formatCtx @@ -333,7 +217,6 @@ - (void) prepareAudioWithFormatContext:(AVFormatContext *)formatCtx return; } - _ring = [[PacketRingBuffer alloc] init]; _audioCodecCtx = avcodec_alloc_context3(audioCodec); avcodec_parameters_to_context(_audioCodecCtx, audioPar); @@ -371,7 +254,6 @@ - (void) prepareAudioWithFormatContext:(AVFormatContext *)formatCtx _lastPTS = 0; _audioClock = av_gettime(); _audioPackets = [[NSMutableArray alloc] init]; - _audioBuffer = [[NSMutableData alloc] init]; _running = YES; } From 4de05f281c8299bab2b5093ae8d579952cceeade Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Tue, 3 Jun 2025 02:19:39 -0400 Subject: [PATCH 36/86] Fix memory leak --- Source/GSMovieView.m | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 403eccecda..afed3b9d7a 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -150,9 +150,9 @@ @interface GSAudioPlayer : NSObject NSThread *_audioThread; } -- (void) prepareAudioWithFormatContext:(AVFormatContext *)formatCtx - streamIndex:(int)audioStreamIndex; -- (void) decodeAudioPacket:(AVPacket *)packet; +- (void) prepareAudioWithFormatContext: (AVFormatContext *)formatCtx + streamIndex: (int)audioStreamIndex; +- (void) decodeAudioPacket: (AVPacket *)packet; - (void) startAudio; - (void) stopAudio; - (void) setVolume: (float)volume; @@ -201,8 +201,8 @@ - (void)dealloc [super dealloc]; } -- (void) prepareAudioWithFormatContext:(AVFormatContext *)formatCtx - streamIndex:(int)audioStreamIndex +- (void) prepareAudioWithFormatContext: (AVFormatContext *)formatCtx + streamIndex: (int)audioStreamIndex { ao_initialize(); int driver = ao_default_driver_id(); @@ -306,7 +306,7 @@ - (void)audioThreadEntry } } -- (void)decodeAudioPacket:(AVPacket *)packet +- (void)decodeAudioPacket: (AVPacket *)packet { if (!_audioCodecCtx || !_swrCtx || !_aoDev) return; @@ -338,7 +338,7 @@ - (void)decodeAudioPacket:(AVPacket *)packet } } -- (void)submitPacket:(AVPacket *)packet +- (void)submitPacket: (AVPacket *)packet { NSDictionary *dict = NSDictionaryFromAVPacket(packet); @synchronized (_audioPackets) @@ -451,7 +451,7 @@ - (NSRect) movieRect (float)_videoCodecCtx->height); } -- (IBAction)gotoPosterFrame:(id)sender +- (IBAction)gotoPosterFrame: (id)sender { NSLog(@"[GSMovieView] gotoPosterFrame called | Timestamp: %ld", av_gettime()); // Reset to first video frame @@ -459,13 +459,13 @@ - (IBAction)gotoPosterFrame:(id)sender [self start: sender]; } -- (IBAction)gotoBeginning:(id)sender +- (IBAction)gotoBeginning: (id)sender { NSLog(@"[GSMovieView] gotoBeginning called | Timestamp: %ld", av_gettime()); [self gotoPosterFrame: sender]; } -- (IBAction)gotoEnd:(id)sender +- (IBAction)gotoEnd: (id)sender { NSURL *url = [[self movie] URL]; NSString *path = [url path]; @@ -631,7 +631,7 @@ - (void) feedVideo avformat_close_input(&formatCtx); } -- (void)prepareVideoWithFormatContext:(AVFormatContext *)formatCtx streamIndex:(int)videoStreamIndex +- (void)prepareVideoWithFormatContext: (AVFormatContext *)formatCtx streamIndex: (int)videoStreamIndex { AVCodecParameters *videoPar = formatCtx->streams[videoStreamIndex]->codecpar; const AVCodec *videoCodec = avcodec_find_decoder(videoPar->codec_id); @@ -685,7 +685,7 @@ - (void) stopVideo } } -- (void)submitVideoPacket:(AVPacket *)packet +- (void)submitVideoPacket: (AVPacket *)packet { NSDictionary *dict = NSDictionaryFromAVPacket(packet); @synchronized (_videoPackets) @@ -748,7 +748,7 @@ - (void)videoThreadEntry } } -- (void)decodeVideoPacket:(AVPacket *)packet +- (void)decodeVideoPacket: (AVPacket *)packet { if (!_videoCodecCtx || !_swsCtx) return; @@ -792,7 +792,8 @@ - (void)decodeVideoPacket:(AVPacket *)packet [self performSelectorOnMainThread: @selector(updateImage:) withObject: image waitUntilDone: NO]; - + + RELEASE(image); RELEASE(bitmap); free(rgbData[0]); } From 2f24c568824609406c4229ce33a10bd1c9e0a6e8 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Tue, 3 Jun 2025 15:33:32 -0400 Subject: [PATCH 37/86] Whitespace cleanup --- Source/GSMovieView.m | 316 ++++++++++++++++++++++--------------------- Source/NSMovie.m | 21 +-- Source/NSMovieView.m | 6 +- 3 files changed, 178 insertions(+), 165 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index afed3b9d7a..8246a95d99 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -67,7 +67,7 @@ static AVPacket AVPacketFromNSDictionary(NSDictionary *dict) NSNumber *pts = [dict objectForKey:@"pts"]; NSNumber *duration = [dict objectForKey:@"duration"]; NSNumber *flags = [dict objectForKey:@"flags"]; - + AVPacket *packet = av_packet_alloc(); packet->data = (uint8_t *)[data bytes]; packet->size = (int)[data length]; @@ -115,7 +115,7 @@ + (NSArray*) movieUnfilteredPasteboardTypes NSMutableArray *result = [NSMutableArray array]; const AVCodec *codec = NULL; void *i = 0; - + while ((codec = av_codec_iterate(&i))) { if (av_codec_is_decoder(codec) && codec->type == AVMEDIA_TYPE_VIDEO) @@ -151,7 +151,7 @@ @interface GSAudioPlayer : NSObject } - (void) prepareAudioWithFormatContext: (AVFormatContext *)formatCtx - streamIndex: (int)audioStreamIndex; + streamIndex: (int)audioStreamIndex; - (void) decodeAudioPacket: (AVPacket *)packet; - (void) startAudio; - (void) stopAudio; @@ -202,12 +202,12 @@ - (void)dealloc } - (void) prepareAudioWithFormatContext: (AVFormatContext *)formatCtx - streamIndex: (int)audioStreamIndex + streamIndex: (int)audioStreamIndex { ao_initialize(); int driver = ao_default_driver_id(); int out_channels = 2; - + AVCodecParameters *audioPar = formatCtx->streams[audioStreamIndex]->codecpar; const AVCodec *audioCodec = avcodec_find_decoder(audioPar->codec_id); @@ -242,7 +242,7 @@ - (void) prepareAudioWithFormatContext: (AVFormatContext *)formatCtx { NSLog(@"[GSMovieView] WARNING: swr_init returned 0"); } - + memset(&_aoFmt, 0, sizeof(ao_sample_format)); _aoFmt.bits = 16; _aoFmt.channels = out_channels; @@ -264,7 +264,7 @@ - (void)audioThreadEntry CREATE_AUTORELEASE_POOL(pool); { NSDictionary *dict = nil; - + @synchronized (_audioPackets) { if (!_started && [_audioPackets count] < 5) @@ -278,13 +278,13 @@ - (void)audioThreadEntry [_audioPackets removeObjectAtIndex:0]; } } - + if (!_started && dict) { _audioClock = av_gettime(); _started = YES; } - + if (dict) { AVPacket packet = AVPacketFromNSDictionary(dict); @@ -293,7 +293,7 @@ - (void)audioThreadEntry int64_t delay = packetTime - now; if (delay > 0) usleep((useconds_t)delay); - + [self decodeAudioPacket:&packet]; [dict release]; } @@ -322,7 +322,7 @@ - (void)decodeAudioPacket: (AVPacket *)packet uint8_t *outPtrs[] = { outBuf }; swr_convert(_swrCtx, outPtrs, outSamples, - (const uint8_t **) _audioFrame->data, + (const uint8_t **) _audioFrame->data, outSamples); // Apply volume @@ -332,7 +332,7 @@ - (void)decodeAudioPacket: (AVPacket *)packet { samples[i] = samples[i] * _volume; } - + ao_play(_aoDev, (char *) outBuf, outBytes); free(outBuf); } @@ -469,7 +469,7 @@ - (IBAction)gotoEnd: (id)sender { NSURL *url = [[self movie] URL]; NSString *path = [url path]; - + NSLog(@"[GSMovieView] gotoEnd called | Timestamp: %ld", av_gettime()); // Seek to the end of the video stream @@ -480,7 +480,7 @@ - (IBAction)gotoEnd: (id)sender { return; } - + if (avformat_find_stream_info(formatCtx, NULL) < 0) { avformat_close_input(&formatCtx); @@ -491,10 +491,10 @@ - (IBAction)gotoEnd: (id)sender for (unsigned int i = 0; i < formatCtx->nb_streams; ++i) { if (formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) - { - videoStream = i; - break; - } + { + videoStream = i; + break; + } } if (videoStream == -1) @@ -541,94 +541,102 @@ - (void) drawRect: (NSRect)dirtyRect - (void) feedVideo { NSMovie *movie = [self movie]; - NSURL *url = [movie URL]; - const char *path = [[url path] UTF8String]; - NSLog(@"[Info] Opening file: %s | Timestamp: %ld", path, av_gettime()); - avformat_network_init(); - AVFormatContext *formatCtx = NULL; - if (avformat_open_input(&formatCtx, path, NULL, NULL) != 0) + if (movie != nil) { - NSLog(@"[Error] Could not open file: %s | Timestamp: %ld", path, av_gettime()); - return; - } + NSURL *url = [movie URL]; - if (avformat_find_stream_info(formatCtx, NULL) < 0) - { - NSLog(@"[Error] Could not find stream info. | Timestamp: %ld", av_gettime()); - avformat_close_input(&formatCtx); - return; - } - - int videoStream = -1; - for (unsigned int i = 0; i < formatCtx->nb_streams; i++) - { - if (formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) - { - videoStream = i; - break; - } - } - - int audioStream = -1; - for (unsigned int i = 0; i < formatCtx->nb_streams; i++) - { - if (formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) - { - audioStream = i; - break; - } - } + if (url != nil) + { + const char *path = [[url path] UTF8String]; + NSLog(@"[Info] Opening file: %s | Timestamp: %ld", path, av_gettime()); + avformat_network_init(); + + AVFormatContext *formatCtx = NULL; + if (avformat_open_input(&formatCtx, path, NULL, NULL) != 0) + { + NSLog(@"[Error] Could not open file: %s | Timestamp: %ld", path, av_gettime()); + return; + } + + if (avformat_find_stream_info(formatCtx, NULL) < 0) + { + NSLog(@"[Error] Could not find stream info. | Timestamp: %ld", av_gettime()); + avformat_close_input(&formatCtx); + return; + } + + int videoStream = -1; + for (unsigned int i = 0; i < formatCtx->nb_streams; i++) + { + if (formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) + { + videoStream = i; + break; + } + } - if (videoStream == -1) - { - NSLog(@"[Error] No video stream found. | Timestamp: %ld", av_gettime()); - avformat_close_input(&formatCtx); - return; - } + int audioStream = -1; + for (unsigned int i = 0; i < formatCtx->nb_streams; i++) + { + if (formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) + { + audioStream = i; + break; + } + } + + if (videoStream == -1) + { + NSLog(@"[Error] No video stream found. | Timestamp: %ld", av_gettime()); + avformat_close_input(&formatCtx); + return; + } + + [self prepareVideoWithFormatContext: formatCtx + streamIndex: videoStream]; + if (audioStream == -1) // if we do have an audio stream, initialize it... otherwise log it + { + NSLog(@"[Info] No audio stream found. | Timestamp: %ld", av_gettime()); + } + else + { + [_audioPlayer prepareAudioWithFormatContext: formatCtx + streamIndex: audioStream]; + } + + AVPacket packet; + int64_t i = 0; + while (av_read_frame(formatCtx, &packet) >= 0) + { + // After 1000 frames, start the thread... + if (i == 1000) + { + [self startVideo]; + [_audioPlayer startAudio]; + } - [self prepareVideoWithFormatContext: formatCtx - streamIndex: videoStream]; - if (audioStream == -1) // if we do have an audio stream, initialize it... otherwise log it - { - NSLog(@"[Info] No audio stream found. | Timestamp: %ld", av_gettime()); - } - else - { - [_audioPlayer prepareAudioWithFormatContext: formatCtx - streamIndex: audioStream]; - } + if (packet.stream_index == videoStream) + [self submitVideoPacket: &packet]; - AVPacket packet; - int64_t i = 0; - while (av_read_frame(formatCtx, &packet) >= 0) - { - // After 1000 frames, start the thread... - if (i == 1000) - { - [self startVideo]; - [_audioPlayer startAudio]; - } - - if (packet.stream_index == videoStream) - [self submitVideoPacket: &packet]; + if (packet.stream_index == audioStream) + [_audioPlayer submitPacket: &packet]; - if (packet.stream_index == audioStream) - [_audioPlayer submitPacket: &packet]; + av_packet_unref(&packet); + i++; + } - av_packet_unref(&packet); - i++; - } + // if we had a very short video... play it. + if (i < 1000) + { + NSLog(@"[GSMovieView] Starting short video... | Timestamp: %ld", av_gettime()); + [self startVideo]; + [_audioPlayer startAudio]; + } - // if we had a very short video... play it. - if (i < 1000) - { - NSLog(@"[GSMovieView] Starting short video... | Timestamp: %ld", av_gettime()); - [self startVideo]; - [_audioPlayer startAudio]; + avformat_close_input(&formatCtx); + } } - - avformat_close_input(&formatCtx); } - (void)prepareVideoWithFormatContext: (AVFormatContext *)formatCtx streamIndex: (int)videoStreamIndex @@ -640,7 +648,7 @@ - (void)prepareVideoWithFormatContext: (AVFormatContext *)formatCtx streamIndex: NSLog(@"[Error] Unsupported video codec. | Timestamp: %ld", av_gettime()); return; } - + _videoCodecCtx = avcodec_alloc_context3(videoCodec); avcodec_parameters_to_context(_videoCodecCtx, videoPar); if (avcodec_open2(_videoCodecCtx, videoCodec, NULL) < 0) @@ -648,11 +656,11 @@ - (void)prepareVideoWithFormatContext: (AVFormatContext *)formatCtx streamIndex: NSLog(@"[Error] Failed to open video codec. | Timestamp: %ld", av_gettime()); return; } - + _videoFrame = av_frame_alloc(); _swsCtx = sws_getContext(videoPar->width, videoPar->height, _videoCodecCtx->pix_fmt, - videoPar->width, videoPar->height, AV_PIX_FMT_RGB24, - SWS_BILINEAR, NULL, NULL, NULL); + videoPar->width, videoPar->height, AV_PIX_FMT_RGB24, + SWS_BILINEAR, NULL, NULL, NULL); _timeBase = formatCtx->streams[videoStreamIndex]->time_base; _videoPackets = RETAIN([[NSMutableArray alloc] init]); @@ -680,7 +688,7 @@ - (void) stopVideo _running = NO; [_videoThread cancel]; while (![_videoThread isFinished]) - usleep(1000); + usleep(1000); DESTROY(_videoThread); } } @@ -699,52 +707,52 @@ - (void)videoThreadEntry while (_running) { CREATE_AUTORELEASE_POOL(pool); - { - NSDictionary *dict = nil; - - @synchronized (_videoPackets) - { - if (!_started && [_videoPackets count] < 3) - { - usleep(5000); + { + NSDictionary *dict = nil; + + @synchronized (_videoPackets) + { + if (!_started && [_videoPackets count] < 3) + { + usleep(5000); RELEASE(pool); - continue; - } - if ([_videoPackets count] > 0) - { - dict = RETAIN([_videoPackets objectAtIndex:0]); - [_videoPackets removeObjectAtIndex:0]; - } - } - - if (!_started && dict) - { - _videoClock = av_gettime(); - _started = YES; - } - - if (dict) - { - AVPacket packet = AVPacketFromNSDictionary(dict); - int64_t packetTime = av_rescale_q(packet.pts, _timeBase, (AVRational){1, 1000000}); - int64_t now = av_gettime() - _videoClock; - int64_t delay = packetTime - now; - - fprintf(stderr, "[GSMovieView] Rendering video frame PTS: %ld | Delay: %ld us\r", packet.pts, delay); - if (delay > 0) + continue; + } + if ([_videoPackets count] > 0) + { + dict = RETAIN([_videoPackets objectAtIndex:0]); + [_videoPackets removeObjectAtIndex:0]; + } + } + + if (!_started && dict) + { + _videoClock = av_gettime(); + _started = YES; + } + + if (dict) + { + AVPacket packet = AVPacketFromNSDictionary(dict); + int64_t packetTime = av_rescale_q(packet.pts, _timeBase, (AVRational){1, 1000000}); + int64_t now = av_gettime() - _videoClock; + int64_t delay = packetTime - now; + + fprintf(stderr, "[GSMovieView] Rendering video frame PTS: %ld | Delay: %ld us\r", packet.pts, delay); + if (delay > 0) { usleep((useconds_t)delay); } - - [self decodeVideoPacket: &packet]; - RELEASE(dict); - } - else - { - usleep(1000); - } + + [self decodeVideoPacket: &packet]; + RELEASE(dict); + } + else + { + usleep(1000); + } RELEASE(pool); - } + } } } @@ -760,21 +768,21 @@ - (void)decodeVideoPacket: (AVPacket *)packet { uint8_t *rgbData[1]; int rgbLineSize[1]; - + int width = _videoCodecCtx->width; int height = _videoCodecCtx->height; - + rgbLineSize[0] = width * 3; rgbData[0] = (uint8_t *)malloc(height * rgbLineSize[0]); - + sws_scale(_swsCtx, - (const uint8_t * const *)_videoFrame->data, - _videoFrame->linesize, - 0, - height, - rgbData, - rgbLineSize); - + (const uint8_t * const *)_videoFrame->data, + _videoFrame->linesize, + 0, + height, + rgbData, + rgbLineSize); + NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: &rgbData[0] pixelsWide: width @@ -786,12 +794,12 @@ - (void)decodeVideoPacket: (AVPacket *)packet colorSpaceName: NSCalibratedRGBColorSpace bytesPerRow: rgbLineSize[0] bitsPerPixel: 24]; - + NSImage *image = [[NSImage alloc] initWithSize: NSMakeSize(width, height)]; [image addRepresentation: bitmap]; [self performSelectorOnMainThread: @selector(updateImage:) withObject: image - waitUntilDone: NO]; + waitUntilDone: NO]; RELEASE(image); RELEASE(bitmap); diff --git a/Source/NSMovie.m b/Source/NSMovie.m index 5eeac64902..32273825b9 100644 --- a/Source/NSMovie.m +++ b/Source/NSMovie.m @@ -23,8 +23,8 @@ You should have received a copy of the GNU Lesser General Public License along with this library; see the file COPYING.LIB. - If not, see or write to the - Free Software Foundation, 51 Franklin Street, Fifth Floor, + If not, see or write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -50,7 +50,7 @@ { return nil; } - + return filepath; } @@ -91,7 +91,7 @@ - (instancetype) initWithData: (NSData *)movie _tmp = YES; ASSIGN(_movie, movie); } - + return self; } @@ -105,9 +105,14 @@ - (instancetype) initWithURL: (NSURL*)url byReference: (BOOL)byRef self = [super init]; if (self != nil) { + if (url == nil) + { + return nil; + } + ASSIGN(_url, url); } - + return self; } @@ -117,13 +122,13 @@ - (instancetype) initWithPasteboard: (NSPasteboard*)pasteboard NSData* data; type = - [pasteboard availableTypeFromArray: + [pasteboard availableTypeFromArray: [object_getClass(self) movieUnfilteredPasteboardTypes]]; if (type == nil) { data = nil; } - else + else { data = [pasteboard dataForType: type]; } @@ -145,7 +150,7 @@ - (void) dealloc [[NSFileManager defaultManager] removeFileAtPath: [_url path] handler: nil]; TEST_RELEASE(_url); TEST_RELEASE(_movie); - + [super dealloc]; } diff --git a/Source/NSMovieView.m b/Source/NSMovieView.m index 8aa53cbae1..a9bcdb74ed 100644 --- a/Source/NSMovieView.m +++ b/Source/NSMovieView.m @@ -23,8 +23,8 @@ You should have received a copy of the GNU Lesser General Public License along with this library; see the file COPYING.LIB. - If not, see or write to the - Free Software Foundation, 51 Franklin Street, Fifth Floor, + If not, see or write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -183,7 +183,7 @@ - (BOOL) playsEveryFrame - (void) showController: (BOOL)show adjustingSize: (BOOL)adjustSize { - _flags.is_controller_visible = show; + _flags.is_controller_visible = show; } - (void*) movieController From 725a1274835329e9f73efd9e4a4b4af8a807d138 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Wed, 4 Jun 2025 00:06:59 -0400 Subject: [PATCH 38/86] Add thread_count and thread_type --- Source/GSMovieView.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 8246a95d99..9cae2223ef 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -657,6 +657,8 @@ - (void)prepareVideoWithFormatContext: (AVFormatContext *)formatCtx streamIndex: return; } + _videoCodecCtx->thread_count = 4; + _videoCodecCtx->thread_type = FF_THREAD_FRAME; _videoFrame = av_frame_alloc(); _swsCtx = sws_getContext(videoPar->width, videoPar->height, _videoCodecCtx->pix_fmt, videoPar->width, videoPar->height, AV_PIX_FMT_RGB24, From 04414e9c6e2990d5cc498503bada81f613e6d9ea Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Wed, 4 Jun 2025 03:01:54 -0400 Subject: [PATCH 39/86] Cleanup and add some missing methods --- Source/GSMovieView.m | 94 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 82 insertions(+), 12 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 9cae2223ef..0f24540465 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -90,7 +90,7 @@ @implementation NSMovie (AVCodec) + (NSArray*) movieUnfilteredFileTypes { - NSMutableSet *extensionsSet = [NSMutableSet set]; + NSMutableSet *extensionsSet = [NSMutableSet set]; void *opaque = NULL; const AVOutputFormat *ofmt = NULL; @@ -100,8 +100,8 @@ + (NSArray*) movieUnfilteredFileTypes if (ofmt->extensions) { NSString *extString = [NSString stringWithUTF8String:ofmt->extensions]; - NSArray *exts = [extString componentsSeparatedByString:@","]; - [extensionsSet addObjectsFromArray:exts]; + NSArray *exts = [extString componentsSeparatedByString:@","]; + [extensionsSet addObjectsFromArray: exts]; } } @@ -112,7 +112,7 @@ + (NSArray*) movieUnfilteredFileTypes + (NSArray*) movieUnfilteredPasteboardTypes { - NSMutableArray *result = [NSMutableArray array]; + NSMutableSet *result = [NSMutableSet set]; const AVCodec *codec = NULL; void *i = 0; @@ -124,7 +124,9 @@ + (NSArray*) movieUnfilteredPasteboardTypes } } - return result; + // Convert to sorted array + NSArray *sorted = [[result allObjects] sortedArrayUsingSelector:@selector(compare:)]; + return sorted; } @end @@ -145,7 +147,9 @@ @interface GSAudioPlayer : NSObject BOOL _running; float _volume; /* 0.0 to 1.0 */ BOOL _started; - + unsigned int _loopMode:3; + BOOL _muted; + NSMutableArray *_audioPackets; NSThread *_audioThread; } @@ -155,8 +159,16 @@ - (void) prepareAudioWithFormatContext: (AVFormatContext *)formatCtx - (void) decodeAudioPacket: (AVPacket *)packet; - (void) startAudio; - (void) stopAudio; + +- (float) volume; - (void) setVolume: (float)volume; +- (NSQTMovieLoopMode) loopMode; +- (void) setLoopMode: (NSQTMovieLoopMode)mode; + +- (BOOL) isMuted; +- (void) setMuted: (BOOL)muted; + @end @implementation GSAudioPlayer @@ -175,6 +187,7 @@ - (instancetype) init _running = NO; _volume = 1.0; _started = NO; + _loopMode = NSQTMovieNormalPlayback; } return self; } @@ -201,6 +214,16 @@ - (void)dealloc [super dealloc]; } +- (NSQTMovieLoopMode) loopMode +{ + return _loopMode; +} + +- (void) setLoopMode: (NSQTMovieLoopMode)mode +{ + _loopMode = mode; +} + - (void) prepareAudioWithFormatContext: (AVFormatContext *)formatCtx streamIndex: (int)audioStreamIndex { @@ -330,7 +353,14 @@ - (void)decodeAudioPacket: (AVPacket *)packet int i = 0; for (i = 0; i < outBytes / 2; ++i) { - samples[i] = samples[i] * _volume; + if ([self isMuted]) + { + samples[i] = 0.0; + } + else + { + samples[i] = samples[i] * _volume; + } } ao_play(_aoDev, (char *) outBuf, outBytes); @@ -371,6 +401,21 @@ - (void) setVolume: (float)volume _volume = volume; } +- (float) volume +{ + return _volume; +} + +- (void) setMuted: (BOOL)muted +{ + _muted = muted; +} + +- (BOOL) isMuted +{ + return _muted; +} + @end // NSMovieView subclass that does all of the actual work of decoding... @@ -390,7 +435,7 @@ - (instancetype) initWithFrame: (NSRect)frame _started = NO; _videoClock = 0; _videoCodecCtx = 0; - _swsCtx = NULL; + _swsCtx = NULL; } return self; } @@ -438,12 +483,30 @@ - (IBAction) stop: (id)sender DESTROY(_feedThread); } +- (void) resetFeed +{ + [self stop: nil]; + [self start: nil]; +} + +- (void) setMuted: (BOOL)muted +{ + [super setMuted: muted]; + [_audioPlayer setMuted: muted]; +} + - (void) setVolume: (float)volume { [super setVolume: volume]; [_audioPlayer setVolume: volume]; } +- (void) setLoopMode: (NSQTMovieLoopMode)mode +{ + [super setLoopMode: mode]; + [self resetFeed]; +} + - (NSRect) movieRect { return NSMakeRect(0.0, 0.0, @@ -454,6 +517,7 @@ - (NSRect) movieRect - (IBAction)gotoPosterFrame: (id)sender { NSLog(@"[GSMovieView] gotoPosterFrame called | Timestamp: %ld", av_gettime()); + // Reset to first video frame [self stop: sender]; [self start: sender]; @@ -462,6 +526,7 @@ - (IBAction)gotoPosterFrame: (id)sender - (IBAction)gotoBeginning: (id)sender { NSLog(@"[GSMovieView] gotoBeginning called | Timestamp: %ld", av_gettime()); + [self gotoPosterFrame: sender]; } @@ -657,12 +722,18 @@ - (void)prepareVideoWithFormatContext: (AVFormatContext *)formatCtx streamIndex: return; } + // Configure the codec... _videoCodecCtx->thread_count = 4; _videoCodecCtx->thread_type = FF_THREAD_FRAME; _videoFrame = av_frame_alloc(); - _swsCtx = sws_getContext(videoPar->width, videoPar->height, _videoCodecCtx->pix_fmt, - videoPar->width, videoPar->height, AV_PIX_FMT_RGB24, - SWS_BILINEAR, NULL, NULL, NULL); + _swsCtx = sws_getContext(videoPar->width, + videoPar->height, + _videoCodecCtx->pix_fmt, + videoPar->width, + videoPar->height, + AV_PIX_FMT_RGB24, + SWS_BILINEAR, + NULL, NULL, NULL); _timeBase = formatCtx->streams[videoStreamIndex]->time_base; _videoPackets = RETAIN([[NSMutableArray alloc] init]); @@ -770,7 +841,6 @@ - (void)decodeVideoPacket: (AVPacket *)packet { uint8_t *rgbData[1]; int rgbLineSize[1]; - int width = _videoCodecCtx->width; int height = _videoCodecCtx->height; From 2e5ec16db43616136b801925c38137f04d65266c Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Wed, 4 Jun 2025 12:02:33 -0400 Subject: [PATCH 40/86] Remove uneeded retain calls --- Source/GSMovieView.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 0f24540465..45e3ccb571 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -430,7 +430,7 @@ - (instancetype) initWithFrame: (NSRect)frame _videoThread = nil; _feedThread = nil; _audioPlayer = [[GSAudioPlayer alloc] init]; - _videoPackets = RETAIN([[NSMutableArray alloc] init]); + _videoPackets = [[NSMutableArray alloc] init]; _running = NO; _started = NO; _videoClock = 0; @@ -469,7 +469,7 @@ - (IBAction) start: (id)sender [self setRate: 1.0 / 30.0]; [self setVolume: 1.0]; - _feedThread = RETAIN([[NSThread alloc] initWithTarget:self selector:@selector(feedVideo) object:nil]); + _feedThread = [[NSThread alloc] initWithTarget:self selector:@selector(feedVideo) object:nil]; [_feedThread start]; [_audioPlayer startAudio]; } @@ -736,7 +736,7 @@ - (void)prepareVideoWithFormatContext: (AVFormatContext *)formatCtx streamIndex: NULL, NULL, NULL); _timeBase = formatCtx->streams[videoStreamIndex]->time_base; - _videoPackets = RETAIN([[NSMutableArray alloc] init]); + _videoPackets = [[NSMutableArray alloc] init]; _videoClock = av_gettime(); _running = NO; _started = NO; @@ -748,7 +748,7 @@ - (void) startVideo if (!_running) { _running = YES; - _videoThread = RETAIN([[NSThread alloc] initWithTarget:self selector:@selector(videoThreadEntry) object:nil]); + _videoThread = [[NSThread alloc] initWithTarget:self selector:@selector(videoThreadEntry) object:nil]; [_videoThread start]; } } From a047612bf34b4cad60d74e4992e0bbce842a5393 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Wed, 4 Jun 2025 20:09:02 -0400 Subject: [PATCH 41/86] Get the size on the main thread instead of getting it from prepare... --- Source/GSMovieView.m | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 45e3ccb571..7d5759522f 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -509,9 +509,39 @@ - (void) setLoopMode: (NSQTMovieLoopMode)mode - (NSRect) movieRect { - return NSMakeRect(0.0, 0.0, - (float)_videoCodecCtx->width, - (float)_videoCodecCtx->height); + AVFormatContext* fmt_ctx = NULL; + // AVCodecContext* codec_ctx = NULL; + NSURL *url = [[self movie] URL]; + const char *name = [[url path] UTF8String]; + + // I realize this is inefficient, but there is a race condition + // which occurs when setting this from the existing stream. + + // Open video file + avformat_open_input(&fmt_ctx, name, NULL, NULL); + avformat_find_stream_info(fmt_ctx, NULL); + + // Find the first video stream + int video_stream_index = -1; + unsigned int i = 0; + for (i = 0; i < fmt_ctx->nb_streams; i++) + { + if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) + { + video_stream_index = i; + break; + } + } + + // Retrieve codec parameters + AVCodecParameters* codecpar = + fmt_ctx->streams[video_stream_index]->codecpar; + + // These are your video dimensions: + CGFloat width = (CGFloat)(codecpar->width); + CGFloat height = (CGFloat)(codecpar->height); + + return NSMakeRect(0.0, 0.0, width, height); } - (IBAction)gotoPosterFrame: (id)sender @@ -793,8 +823,8 @@ - (void)videoThreadEntry } if ([_videoPackets count] > 0) { - dict = RETAIN([_videoPackets objectAtIndex:0]); - [_videoPackets removeObjectAtIndex:0]; + dict = RETAIN([_videoPackets objectAtIndex: 0]); + [_videoPackets removeObjectAtIndex: 0]; } } From c8d40f51afd8f4ca6e55d876eb2739361cdbf004 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Wed, 4 Jun 2025 21:03:47 -0400 Subject: [PATCH 42/86] Minor cleanup --- Source/GSMovieView.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 7d5759522f..01864e9a2a 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -510,7 +510,6 @@ - (void) setLoopMode: (NSQTMovieLoopMode)mode - (NSRect) movieRect { AVFormatContext* fmt_ctx = NULL; - // AVCodecContext* codec_ctx = NULL; NSURL *url = [[self movie] URL]; const char *name = [[url path] UTF8String]; @@ -738,6 +737,7 @@ - (void)prepareVideoWithFormatContext: (AVFormatContext *)formatCtx streamIndex: { AVCodecParameters *videoPar = formatCtx->streams[videoStreamIndex]->codecpar; const AVCodec *videoCodec = avcodec_find_decoder(videoPar->codec_id); + if (!videoCodec) { NSLog(@"[Error] Unsupported video codec. | Timestamp: %ld", av_gettime()); From 708a2da42b58c6fc91e6d57f2343b54057acd414 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Wed, 4 Jun 2025 21:54:09 -0400 Subject: [PATCH 43/86] terminate the thread, cleanup --- Source/GSMovieView.m | 47 +++++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 01864e9a2a..d69657eac0 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -444,17 +444,31 @@ - (void)dealloc { [self stop: nil]; + if (_feedThread) + { + [_feedThread cancel]; + DESTROY(_feedThread); + } + if (_videoFrame) - av_frame_free(&_videoFrame); + { + av_frame_free(&_videoFrame); + } + if (_videoCodecCtx) - avcodec_free_context(&_videoCodecCtx); + { + avcodec_free_context(&_videoCodecCtx); + } + if (_swsCtx) - sws_freeContext(_swsCtx); - - DESTROY(_videoPackets); + { + sws_freeContext(_swsCtx); + } + TEST_RELEASE(_currentFrame); + DESTROY(_videoPackets); DESTROY(_audioPlayer); - + [super dealloc]; } @@ -680,15 +694,18 @@ - (void) feedVideo } } + // Video stream... if (videoStream == -1) { - NSLog(@"[Error] No video stream found. | Timestamp: %ld", av_gettime()); - avformat_close_input(&formatCtx); - return; + NSLog(@"[Info] No video stream found. | Timestamp: %ld", av_gettime()); + } + else + { + [self prepareVideoWithFormatContext: formatCtx + streamIndex: videoStream]; } - [self prepareVideoWithFormatContext: formatCtx - streamIndex: videoStream]; + // Audio stream... if (audioStream == -1) // if we do have an audio stream, initialize it... otherwise log it { NSLog(@"[Info] No audio stream found. | Timestamp: %ld", av_gettime()); @@ -699,6 +716,14 @@ - (void) feedVideo streamIndex: audioStream]; } + // Video and Audio stream not present... + if (videoStream == -1 && audioStream == -1) + { + NSLog(@"[Error] No video or audio stream detected, exiting"); + avformat_close_input(&formatCtx); + return; + } + AVPacket packet; int64_t i = 0; while (av_read_frame(formatCtx, &packet) >= 0) From c775466bb04a3b9ce3991f13a7ee0037cb6e5b33 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Wed, 4 Jun 2025 22:47:36 -0400 Subject: [PATCH 44/86] Add stream indexes to the object --- Source/GSMovieView.h | 5 +- Source/GSMovieView.m | 127 +++++++++++++++++-------------------------- 2 files changed, 54 insertions(+), 78 deletions(-) diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index bfa0ec7a81..755aabff62 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -65,6 +65,8 @@ APPKIT_EXPORT_CLASS BOOL _running; BOOL _started; int64_t _videoClock; + int _videoStreamIndex; + int _audioStreamIndex; } - (void) prepareVideoWithFormatContext: (AVFormatContext *)formatCtx @@ -74,8 +76,7 @@ APPKIT_EXPORT_CLASS - (void) startVideo; - (void) stopVideo; - (void) feedVideo; -// - (void) logStreamMetadata; @end -#endif /* _GNUstep_H_NSMovieView */ +#endif /* _GNUstep_H_GSMovieView */ diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index d69657eac0..b94511785c 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -141,7 +141,6 @@ @interface GSAudioPlayer : NSObject SwrContext *_swrCtx; ao_device *_aoDev; ao_sample_format _aoFmt; - int64_t _lastPTS; int64_t _audioClock; AVRational _timeBase; BOOL _running; @@ -180,7 +179,6 @@ - (instancetype) init _audioCodecCtx = NULL; _audioFrame = NULL; _swrCtx = NULL; - _lastPTS = 0; _audioClock = 0; _audioPackets = nil; _audioThread = nil; @@ -197,17 +195,25 @@ - (void)dealloc [self stopAudio]; if (_audioFrame) - av_frame_free(&_audioFrame); - + { + av_frame_free(&_audioFrame); + } + if (_audioCodecCtx) - avcodec_free_context(&_audioCodecCtx); - + { + avcodec_free_context(&_audioCodecCtx); + } + if (_swrCtx) - swr_free(&_swrCtx); + { + swr_free(&_swrCtx); + } if (_aoDev) - ao_close(_aoDev); - + { + ao_close(_aoDev); + } + RELEASE(_audioPackets); ao_shutdown(); @@ -274,7 +280,6 @@ - (void) prepareAudioWithFormatContext: (AVFormatContext *)formatCtx _aoDev = ao_open_live(driver, &_aoFmt, NULL); _timeBase = formatCtx->streams[audioStreamIndex]->time_base; - _lastPTS = 0; _audioClock = av_gettime(); _audioPackets = [[NSMutableArray alloc] init]; _running = YES; @@ -388,16 +393,27 @@ - (void)stopAudio { _running = NO; [_audioThread cancel]; - while (![_audioThread isFinished]) - usleep(1000); - [_audioThread release]; - _audioThread = nil; + + while ([_audioThread isFinished] == NO) + { + usleep(1000); + } + + DESTROY(_audioThread); } - (void) setVolume: (float)volume { - if (volume < 0.0) volume = 0.0; - if (volume > 1.0) volume = 1.0; + if (volume < 0.0) + { + volume = 0.0; + } + + if (volume > 1.0) + { + volume = 1.0; + } + _volume = volume; } @@ -575,50 +591,6 @@ - (IBAction)gotoBeginning: (id)sender - (IBAction)gotoEnd: (id)sender { - NSURL *url = [[self movie] URL]; - NSString *path = [url path]; - - NSLog(@"[GSMovieView] gotoEnd called | Timestamp: %ld", av_gettime()); - - // Seek to the end of the video stream - [self stop: sender]; - - AVFormatContext *formatCtx = NULL; - if (avformat_open_input(&formatCtx, [path UTF8String], NULL, NULL) != 0) - { - return; - } - - if (avformat_find_stream_info(formatCtx, NULL) < 0) - { - avformat_close_input(&formatCtx); - return; - } - - int videoStream = -1; - for (unsigned int i = 0; i < formatCtx->nb_streams; ++i) - { - if (formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) - { - videoStream = i; - break; - } - } - - if (videoStream == -1) - { - avformat_close_input(&formatCtx); - return; - } - - int64_t duration = formatCtx->streams[videoStream]->duration; - // AVRational timeBase = formatCtx->streams[videoStream]->time_base; - - int64_t seekTarget = duration - AV_TIME_BASE; - av_seek_frame(formatCtx, videoStream, seekTarget, AVSEEK_FLAG_BACKWARD); - - [self feedVideo]; - avformat_close_input(&formatCtx); } - (IBAction) stepForward: (id)sender @@ -630,7 +602,6 @@ - (IBAction) stepBack: (id)sender } // Video playback methods... - - (void) updateImage: (NSImage *)image { ASSIGN(_currentFrame, image); @@ -674,50 +645,50 @@ - (void) feedVideo return; } - int videoStream = -1; + _videoStreamIndex = -1; for (unsigned int i = 0; i < formatCtx->nb_streams; i++) { if (formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { - videoStream = i; + _videoStreamIndex = i; break; } } - int audioStream = -1; + _audioStreamIndex = -1; for (unsigned int i = 0; i < formatCtx->nb_streams; i++) { if (formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { - audioStream = i; + _audioStreamIndex = i; break; } } // Video stream... - if (videoStream == -1) + if (_videoStreamIndex == -1) { NSLog(@"[Info] No video stream found. | Timestamp: %ld", av_gettime()); } else { [self prepareVideoWithFormatContext: formatCtx - streamIndex: videoStream]; + streamIndex: _videoStreamIndex]; } // Audio stream... - if (audioStream == -1) // if we do have an audio stream, initialize it... otherwise log it + if (_audioStreamIndex == -1) // if we do have an audio stream, initialize it... otherwise log it { NSLog(@"[Info] No audio stream found. | Timestamp: %ld", av_gettime()); } else { [_audioPlayer prepareAudioWithFormatContext: formatCtx - streamIndex: audioStream]; + streamIndex: _audioStreamIndex]; } // Video and Audio stream not present... - if (videoStream == -1 && audioStream == -1) + if (_videoStreamIndex == -1 && _audioStreamIndex == -1) { NSLog(@"[Error] No video or audio stream detected, exiting"); avformat_close_input(&formatCtx); @@ -735,12 +706,16 @@ - (void) feedVideo [_audioPlayer startAudio]; } - if (packet.stream_index == videoStream) - [self submitVideoPacket: &packet]; - - if (packet.stream_index == audioStream) - [_audioPlayer submitPacket: &packet]; - + if (packet.stream_index == _videoStreamIndex) + { + [self submitVideoPacket: &packet]; + } + + if (packet.stream_index == _audioStreamIndex) + { + [_audioPlayer submitPacket: &packet]; + } + av_packet_unref(&packet); i++; } From 39d05cebb1c5a2456a8fef28fe6b4ac79af8ccdd Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Thu, 5 Jun 2025 02:50:15 -0400 Subject: [PATCH 45/86] Implement gotoEnd, gotoBeginning, etc --- Source/GSMovieView.m | 123 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 99 insertions(+), 24 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index b94511785c..ca7349fb4e 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -148,7 +148,7 @@ @interface GSAudioPlayer : NSObject BOOL _started; unsigned int _loopMode:3; BOOL _muted; - + NSMutableArray *_audioPackets; NSThread *_audioThread; } @@ -198,12 +198,12 @@ - (void)dealloc { av_frame_free(&_audioFrame); } - + if (_audioCodecCtx) { avcodec_free_context(&_audioCodecCtx); } - + if (_swrCtx) { swr_free(&_swrCtx); @@ -213,7 +213,7 @@ - (void)dealloc { ao_close(_aoDev); } - + RELEASE(_audioPackets); ao_shutdown(); @@ -398,7 +398,7 @@ - (void)stopAudio { usleep(1000); } - + DESTROY(_audioThread); } @@ -408,12 +408,12 @@ - (void) setVolume: (float)volume { volume = 0.0; } - + if (volume > 1.0) { volume = 1.0; } - + _volume = volume; } @@ -451,7 +451,7 @@ - (instancetype) initWithFrame: (NSRect)frame _started = NO; _videoClock = 0; _videoCodecCtx = 0; - _swsCtx = NULL; + _swsCtx = NULL; } return self; } @@ -465,26 +465,26 @@ - (void)dealloc [_feedThread cancel]; DESTROY(_feedThread); } - + if (_videoFrame) { av_frame_free(&_videoFrame); } - + if (_videoCodecCtx) { avcodec_free_context(&_videoCodecCtx); } - + if (_swsCtx) { sws_freeContext(_swsCtx); } - + TEST_RELEASE(_currentFrame); DESTROY(_videoPackets); DESTROY(_audioPlayer); - + [super dealloc]; } @@ -545,7 +545,7 @@ - (NSRect) movieRect // I realize this is inefficient, but there is a race condition // which occurs when setting this from the existing stream. - + // Open video file avformat_open_input(&fmt_ctx, name, NULL, NULL); avformat_find_stream_info(fmt_ctx, NULL); @@ -573,24 +573,99 @@ - (NSRect) movieRect return NSMakeRect(0.0, 0.0, width, height); } +- (void) _gotoFrame: (int64_t)pts +{ + AVPacket pkt; + AVFormatContext *fmt_ctx = NULL; + NSURL *url = [[self movie] URL]; + const char *name = [[url path] UTF8String]; + + [self stop: nil]; + + // Open video file + avformat_open_input(&fmt_ctx, name, NULL, NULL); + avformat_find_stream_info(fmt_ctx, NULL); + + // Find the first video stream + int video_stream_index = -1; + unsigned int i = 0; + for (i = 0; i < fmt_ctx->nb_streams; i++) + { + if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) + { + video_stream_index = i; + break; + } + } + + // Get the first decoded frame, show that... + while (av_read_frame(fmt_ctx, &pkt) >= pts) + { + if (pkt.stream_index == video_stream_index) + { + [self decodeVideoPacket: &pkt]; + } + av_packet_unref(&pkt); + } +} + - (IBAction)gotoPosterFrame: (id)sender { + [self _gotoFrame: 0]; NSLog(@"[GSMovieView] gotoPosterFrame called | Timestamp: %ld", av_gettime()); - - // Reset to first video frame - [self stop: sender]; - [self start: sender]; } - (IBAction)gotoBeginning: (id)sender { + [self _gotoFrame: 0]; NSLog(@"[GSMovieView] gotoBeginning called | Timestamp: %ld", av_gettime()); - - [self gotoPosterFrame: sender]; } - (IBAction)gotoEnd: (id)sender { + AVFormatContext *fmt_ctx = NULL; + NSURL *url = [[self movie] URL]; + const char *name = [[url path] UTF8String]; + + [self stop: nil]; + + // Open video file + avformat_open_input(&fmt_ctx, name, NULL, NULL); + + // Find the first video stream + int video_stream_index = -1; + unsigned int i = 0; + for (i = 0; i < fmt_ctx->nb_streams; i++) + { + if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) + { + video_stream_index = i; + break; + } + } + + // Find and decode the packet + AVPacket pkt; + int64_t last_pts = AV_NOPTS_VALUE; + av_seek_frame(fmt_ctx, video_stream_index, INT64_MAX, AVSEEK_FLAG_BACKWARD); + while (av_read_frame(fmt_ctx, &pkt) >= 0) + { + if (pkt.stream_index == video_stream_index) + { + if (pkt.pts != AV_NOPTS_VALUE) + { + last_pts = pkt.pts; + } + } + av_packet_unref(&pkt); + } + + if (last_pts != AV_NOPTS_VALUE) + { + double seconds = last_pts * av_q2d(fmt_ctx->streams[video_stream_index]->time_base); + [self _gotoFrame: last_pts]; + NSLog(@"Last decoded PTS: %" PRId64 " (%.3f sec)\n", last_pts, seconds); + } } - (IBAction) stepForward: (id)sender @@ -627,11 +702,11 @@ - (void) feedVideo if (url != nil) { + AVFormatContext *formatCtx = NULL; const char *path = [[url path] UTF8String]; + NSLog(@"[Info] Opening file: %s | Timestamp: %ld", path, av_gettime()); avformat_network_init(); - - AVFormatContext *formatCtx = NULL; if (avformat_open_input(&formatCtx, path, NULL, NULL) != 0) { NSLog(@"[Error] Could not open file: %s | Timestamp: %ld", path, av_gettime()); @@ -710,12 +785,12 @@ - (void) feedVideo { [self submitVideoPacket: &packet]; } - + if (packet.stream_index == _audioStreamIndex) { [_audioPlayer submitPacket: &packet]; } - + av_packet_unref(&packet); i++; } From 72438048e4b439f697dd6a7692f184972aa92a55 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Thu, 5 Jun 2025 03:43:23 -0400 Subject: [PATCH 46/86] Improve methods, add debugging info --- Source/GSMovieView.m | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index ca7349fb4e..0e3b94dd77 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -496,21 +496,27 @@ - (BOOL) isPlaying - (IBAction) start: (id)sender { - [self setRate: 1.0 / 30.0]; - [self setVolume: 1.0]; + if (_running == NO) + { + [self setRate: 1.0 / 30.0]; + [self setVolume: 1.0]; - _feedThread = [[NSThread alloc] initWithTarget:self selector:@selector(feedVideo) object:nil]; - [_feedThread start]; - [_audioPlayer startAudio]; + _feedThread = [[NSThread alloc] initWithTarget:self selector:@selector(feedVideo) object:nil]; + [_feedThread start]; + [_audioPlayer startAudio]; + } } - (IBAction) stop: (id)sender { - [_feedThread cancel]; - [self stopVideo]; - [_audioPlayer stopAudio]; - - DESTROY(_feedThread); + if (_running) + { + [_feedThread cancel]; + [self stopVideo]; + [_audioPlayer stopAudio]; + + DESTROY(_feedThread); + } } - (void) resetFeed @@ -626,10 +632,12 @@ - (IBAction)gotoEnd: (id)sender AVFormatContext *fmt_ctx = NULL; NSURL *url = [[self movie] URL]; const char *name = [[url path] UTF8String]; - + + NSLog(@"Stopping..."); [self stop: nil]; // Open video file + NSLog(@"Name... %s", name); avformat_open_input(&fmt_ctx, name, NULL, NULL); // Find the first video stream @@ -644,6 +652,7 @@ - (IBAction)gotoEnd: (id)sender } } + NSLog(@"stream = %d", video_stream_index); // Find and decode the packet AVPacket pkt; int64_t last_pts = AV_NOPTS_VALUE; @@ -660,6 +669,8 @@ - (IBAction)gotoEnd: (id)sender av_packet_unref(&pkt); } + NSLog(@"last_pts = %ld", last_pts); + if (last_pts != AV_NOPTS_VALUE) { double seconds = last_pts * av_q2d(fmt_ctx->streams[video_stream_index]->time_base); From 67f8966bdc8aadb1e373da3a2290ce27cc063a76 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Sat, 7 Jun 2025 02:55:02 -0400 Subject: [PATCH 47/86] Fixing stop/start/goto methods --- Source/GSMovieView.h | 10 ++ Source/GSMovieView.m | 292 ++++++++++++++++++++++++++++--------------- Source/NSMovieView.m | 8 ++ 3 files changed, 209 insertions(+), 101 deletions(-) diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index 755aabff62..ad74f75f9b 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -59,6 +59,7 @@ APPKIT_EXPORT_CLASS AVCodecContext *_videoCodecCtx; AVFrame *_videoFrame; + AVFormatContext *_formatCtx; struct SwsContext *_swsCtx; AVRational _timeBase; @@ -67,14 +68,23 @@ APPKIT_EXPORT_CLASS int64_t _videoClock; int _videoStreamIndex; int _audioStreamIndex; + int64_t _lastPts; + int64_t _savedPts; } +// Initialization... - (void) prepareVideoWithFormatContext: (AVFormatContext *)formatCtx streamIndex: (int)videoStreamIndex; + +// Submit packets... - (void) submitVideoPacket: (AVPacket *)packet; - (void) decodeVideoPacket: (AVPacket *)packet; + +// Start and stop... - (void) startVideo; - (void) stopVideo; + +// Main loop to process packets... - (void) feedVideo; @end diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 0e3b94dd77..323438145f 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -78,6 +78,64 @@ static AVPacket AVPacketFromNSDictionary(NSDictionary *dict) return *packet; } +/* +BOOL seek_to_pts(AVFormatContext *fmt_ctx, + AVCodecContext *codec_ctx, + int stream_index, + int64_t target_pts) +{ + AVPacket pkt; + AVFrame *frame = av_frame_alloc(); + BOOL found = NO; + + NSLog(@"[GSMovieView] stream_index = %d, target_pts = %ld", stream_index, target_pts); + + // No frame + if (!frame) + { + NSLog(@"[GSMovieView] No AVFrame allocated"); + return NO; + } + + // Seek near the target timestamp (in stream time_base units) + if (av_seek_frame(fmt_ctx, stream_index, target_pts, AVSEEK_FLAG_BACKWARD) < 0) + { + NSLog(@"[GSMovieView] Error seeking\n"); + av_frame_free(&frame); + return NO; + } + + avcodec_flush_buffers(codec_ctx); + + // Read packets until desired frame is found + while (av_read_frame(fmt_ctx, &pkt) >= 0) + { + if (pkt.stream_index == stream_index) + { + if (avcodec_send_packet(codec_ctx, &pkt) == 0) + { + while (avcodec_receive_frame(codec_ctx, frame) == 0) + { + if (frame->pts >= target_pts) + { + found = YES; + break; + } + } + } + } + av_packet_unref(&pkt); + if (found) + { + break; + } + } + + av_frame_free(&frame); + return found; +} +*/ + // Ignore the warning this will produce as it is intentional. #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation" @@ -450,8 +508,10 @@ - (instancetype) initWithFrame: (NSRect)frame _running = NO; _started = NO; _videoClock = 0; - _videoCodecCtx = 0; + _videoCodecCtx = NULL; + _formatCtx = NULL; _swsCtx = NULL; + _lastPts = 0; } return self; } @@ -488,6 +548,36 @@ - (void)dealloc [super dealloc]; } +// Private methods... +- (void) _resetFeed +{ + [self stop: nil]; + [self start: nil]; +} + +/* +- (void) _gotoFrame: (int64_t)pts +{ + BOOL success = [self reset]; + + if(success) + { + success = seek_to_pts(_formatCtx, + _videoCodecCtx, + _videoStreamIndex, + _lastPts); + if (!success) + { + NSLog(@"Failed to seek to frame"); + } + } + else + { + NSLog(@"Failed to reset frame"); + } +} +*/ + // Overridden methods from the superclass... - (BOOL) isPlaying { @@ -519,12 +609,6 @@ - (IBAction) stop: (id)sender } } -- (void) resetFeed -{ - [self stop: nil]; - [self start: nil]; -} - - (void) setMuted: (BOOL)muted { [super setMuted: muted]; @@ -540,7 +624,6 @@ - (void) setVolume: (float)volume - (void) setLoopMode: (NSQTMovieLoopMode)mode { [super setLoopMode: mode]; - [self resetFeed]; } - (NSRect) movieRect @@ -551,7 +634,9 @@ - (NSRect) movieRect // I realize this is inefficient, but there is a race condition // which occurs when setting this from the existing stream. - + // The issue with using the ivars is that they are initialized on + // a thread, so they may not be set when this is called. + // Open video file avformat_open_input(&fmt_ctx, name, NULL, NULL); avformat_find_stream_info(fmt_ctx, NULL); @@ -579,51 +664,17 @@ - (NSRect) movieRect return NSMakeRect(0.0, 0.0, width, height); } -- (void) _gotoFrame: (int64_t)pts -{ - AVPacket pkt; - AVFormatContext *fmt_ctx = NULL; - NSURL *url = [[self movie] URL]; - const char *name = [[url path] UTF8String]; - - [self stop: nil]; - - // Open video file - avformat_open_input(&fmt_ctx, name, NULL, NULL); - avformat_find_stream_info(fmt_ctx, NULL); - - // Find the first video stream - int video_stream_index = -1; - unsigned int i = 0; - for (i = 0; i < fmt_ctx->nb_streams; i++) - { - if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) - { - video_stream_index = i; - break; - } - } - - // Get the first decoded frame, show that... - while (av_read_frame(fmt_ctx, &pkt) >= pts) - { - if (pkt.stream_index == video_stream_index) - { - [self decodeVideoPacket: &pkt]; - } - av_packet_unref(&pkt); - } -} - - (IBAction)gotoPosterFrame: (id)sender { - [self _gotoFrame: 0]; + _savedPts = 0.0; + [self _resetFeed]; NSLog(@"[GSMovieView] gotoPosterFrame called | Timestamp: %ld", av_gettime()); } - (IBAction)gotoBeginning: (id)sender { - [self _gotoFrame: 0]; + _savedPts = 0.0; + [self _resetFeed]; NSLog(@"[GSMovieView] gotoBeginning called | Timestamp: %ld", av_gettime()); } @@ -674,7 +725,7 @@ - (IBAction)gotoEnd: (id)sender if (last_pts != AV_NOPTS_VALUE) { double seconds = last_pts * av_q2d(fmt_ctx->streams[video_stream_index]->time_base); - [self _gotoFrame: last_pts]; + // [self _gotoFrame: last_pts]; NSLog(@"Last decoded PTS: %" PRId64 " (%.3f sec)\n", last_pts, seconds); } } @@ -713,28 +764,28 @@ - (void) feedVideo if (url != nil) { - AVFormatContext *formatCtx = NULL; const char *path = [[url path] UTF8String]; NSLog(@"[Info] Opening file: %s | Timestamp: %ld", path, av_gettime()); avformat_network_init(); - if (avformat_open_input(&formatCtx, path, NULL, NULL) != 0) + if (avformat_open_input(&_formatCtx, path, NULL, NULL) != 0) { NSLog(@"[Error] Could not open file: %s | Timestamp: %ld", path, av_gettime()); return; } - if (avformat_find_stream_info(formatCtx, NULL) < 0) + // NSLog(@"_formatCtx = %lld", _formatCtx); + if (avformat_find_stream_info(_formatCtx, NULL) < 0) { NSLog(@"[Error] Could not find stream info. | Timestamp: %ld", av_gettime()); - avformat_close_input(&formatCtx); + avformat_close_input(&_formatCtx); return; } _videoStreamIndex = -1; - for (unsigned int i = 0; i < formatCtx->nb_streams; i++) + for (unsigned int i = 0; i < _formatCtx->nb_streams; i++) { - if (formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) + if (_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { _videoStreamIndex = i; break; @@ -742,9 +793,9 @@ - (void) feedVideo } _audioStreamIndex = -1; - for (unsigned int i = 0; i < formatCtx->nb_streams; i++) + for (unsigned int i = 0; i < _formatCtx->nb_streams; i++) { - if (formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) + if (_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { _audioStreamIndex = i; break; @@ -758,7 +809,7 @@ - (void) feedVideo } else { - [self prepareVideoWithFormatContext: formatCtx + [self prepareVideoWithFormatContext: _formatCtx streamIndex: _videoStreamIndex]; } @@ -769,7 +820,7 @@ - (void) feedVideo } else { - [_audioPlayer prepareAudioWithFormatContext: formatCtx + [_audioPlayer prepareAudioWithFormatContext: _formatCtx streamIndex: _audioStreamIndex]; } @@ -777,44 +828,56 @@ - (void) feedVideo if (_videoStreamIndex == -1 && _audioStreamIndex == -1) { NSLog(@"[Error] No video or audio stream detected, exiting"); - avformat_close_input(&formatCtx); + avformat_close_input(&_formatCtx); return; } - AVPacket packet; - int64_t i = 0; - while (av_read_frame(formatCtx, &packet) >= 0) + // Seek to the current PTS... + BOOL success = YES; + + // seek_to_pts(_formatCtx, + // _videoCodecCtx, + // _videoStreamIndex, + // _lastPts); + + if (success) { - // After 1000 frames, start the thread... - if (i == 1000) - { - [self startVideo]; - [_audioPlayer startAudio]; - } + AVPacket packet; + int64_t i = 0; - if (packet.stream_index == _videoStreamIndex) + while (av_read_frame(_formatCtx, &packet) >= 0) { - [self submitVideoPacket: &packet]; + // After 1000 frames, start the thread... + if (i == 1000) + { + [self startVideo]; + [_audioPlayer startAudio]; + } + + if (packet.stream_index == _videoStreamIndex) + { + [self submitVideoPacket: &packet]; + } + + if (packet.stream_index == _audioStreamIndex) + { + [_audioPlayer submitPacket: &packet]; + } + + av_packet_unref(&packet); + i++; } - if (packet.stream_index == _audioStreamIndex) + // if we had a very short video... play it. + if (i < 1000) { - [_audioPlayer submitPacket: &packet]; + NSLog(@"[GSMovieView] Starting short video... | Timestamp: %ld", av_gettime()); + [self startVideo]; + [_audioPlayer startAudio]; } - - av_packet_unref(&packet); - i++; - } - - // if we had a very short video... play it. - if (i < 1000) - { - NSLog(@"[GSMovieView] Starting short video... | Timestamp: %ld", av_gettime()); - [self startVideo]; - [_audioPlayer startAudio]; } - - avformat_close_input(&formatCtx); + + avformat_close_input(&_formatCtx); } } } @@ -860,7 +923,7 @@ - (void)prepareVideoWithFormatContext: (AVFormatContext *)formatCtx streamIndex: - (void) startVideo { - NSLog(@"[GSMovieView] Starting video thread | Timestamp: %ld", av_gettime()); + NSLog(@"[GSMovieView] Starting video thread | Timestamp: %ld, lastPts = %ld", av_gettime(), _lastPts); if (!_running) { _running = YES; @@ -871,14 +934,22 @@ - (void) startVideo - (void) stopVideo { - NSLog(@"[GSMovieView] Stopping video thread | Timestamp: %ld", av_gettime()); + NSLog(@"[GSMovieView] Stopping video thread | Timestamp: %ld, lastPts = %ld", av_gettime(), _lastPts); if (_running) { _running = NO; + [_videoThread cancel]; while (![_videoThread isFinished]) - usleep(1000); + { + usleep(1000); + } + DESTROY(_videoThread); + avformat_close_input(&_formatCtx); + + _savedPts = _lastPts; + _lastPts = 0; } } @@ -899,6 +970,8 @@ - (void)videoThreadEntry { NSDictionary *dict = nil; + // Pop the video packet off _videoPackets, sync on + // the array. @synchronized (_videoPackets) { if (!_started && [_videoPackets count] < 3) @@ -914,32 +987,47 @@ - (void)videoThreadEntry } } + // If the dict is present and the thread is started, get + // the clock. if (!_started && dict) { _videoClock = av_gettime(); _started = YES; } + // If dict is not nil, decode it and get the frame... if (dict) { AVPacket packet = AVPacketFromNSDictionary(dict); - int64_t packetTime = av_rescale_q(packet.pts, _timeBase, (AVRational){1, 1000000}); - int64_t now = av_gettime() - _videoClock; - int64_t delay = packetTime - now; - fprintf(stderr, "[GSMovieView] Rendering video frame PTS: %ld | Delay: %ld us\r", packet.pts, delay); - if (delay > 0) + // If the current pts is at or after the saved, + // then alow it to be decoded and displayed... + if (packet.pts >= _savedPts) { - usleep((useconds_t)delay); + int64_t packetTime = av_rescale_q(packet.pts, + _timeBase, + (AVRational){1, 1000000}); + int64_t now = av_gettime() - _videoClock; + int64_t delay = packetTime - now; + + // Show the information... + fprintf(stderr, "[GSMovieView] Rendering video frame PTS: %ld | Delay: %ld us\r", + packet.pts, delay); + if (delay > 0) + { + usleep((useconds_t)delay); + } + + // Decode the packet, display it and play the sound... + [self decodeVideoPacket: &packet]; + RELEASE(dict); + } + else + { + usleep(1000); } - - [self decodeVideoPacket: &packet]; - RELEASE(dict); - } - else - { - usleep(1000); } + RELEASE(pool); } } @@ -953,6 +1041,8 @@ - (void)decodeVideoPacket: (AVPacket *)packet if (avcodec_send_packet(_videoCodecCtx, packet) < 0) return; + _lastPts = packet->pts; + while (avcodec_receive_frame(_videoCodecCtx, _videoFrame) == 0) { uint8_t *rgbData[1]; diff --git a/Source/NSMovieView.m b/Source/NSMovieView.m index a9bcdb74ed..22c7ccab71 100644 --- a/Source/NSMovieView.m +++ b/Source/NSMovieView.m @@ -134,6 +134,14 @@ - (float) rate - (void) setVolume: (float)volume { _volume = volume; + if (volume <= 0.0) + { + _flags.muted = YES; + } + else if (volume > 0.0) + { + _flags.muted = NO; + } } - (float) volume From 60cf0fd0b6585809587933859b80a39219e32797 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Sat, 7 Jun 2025 05:11:53 -0400 Subject: [PATCH 48/86] Add notification handler to shut down the threads --- Source/GSMovieView.h | 1 + Source/GSMovieView.m | 200 ++++++++++++++++--------------------------- 2 files changed, 76 insertions(+), 125 deletions(-) diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index ad74f75f9b..9f447a5585 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -56,6 +56,7 @@ APPKIT_EXPORT_CLASS NSThread *_feedThread; NSImage *_currentFrame; GSAudioPlayer *_audioPlayer; + NSString *_statusString; AVCodecContext *_videoCodecCtx; AVFrame *_videoFrame; diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 323438145f..3a4ddf2912 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -30,10 +30,12 @@ #import #import +#import #import #import #import +#import "AppKit/NSApplication.h" #import "AppKit/NSColor.h" #import "AppKit/NSGraphics.h" #import "AppKit/NSImage.h" @@ -46,6 +48,8 @@ #include +static NSNotificationCenter *nc = nil; + static NSDictionary *NSDictionaryFromAVPacket(AVPacket *packet) { NSData *data = [NSData dataWithBytes:packet->data length:packet->size]; @@ -78,64 +82,6 @@ static AVPacket AVPacketFromNSDictionary(NSDictionary *dict) return *packet; } -/* -BOOL seek_to_pts(AVFormatContext *fmt_ctx, - AVCodecContext *codec_ctx, - int stream_index, - int64_t target_pts) -{ - AVPacket pkt; - AVFrame *frame = av_frame_alloc(); - BOOL found = NO; - - NSLog(@"[GSMovieView] stream_index = %d, target_pts = %ld", stream_index, target_pts); - - // No frame - if (!frame) - { - NSLog(@"[GSMovieView] No AVFrame allocated"); - return NO; - } - - // Seek near the target timestamp (in stream time_base units) - if (av_seek_frame(fmt_ctx, stream_index, target_pts, AVSEEK_FLAG_BACKWARD) < 0) - { - NSLog(@"[GSMovieView] Error seeking\n"); - av_frame_free(&frame); - return NO; - } - - avcodec_flush_buffers(codec_ctx); - - // Read packets until desired frame is found - while (av_read_frame(fmt_ctx, &pkt) >= 0) - { - if (pkt.stream_index == stream_index) - { - if (avcodec_send_packet(codec_ctx, &pkt) == 0) - { - while (avcodec_receive_frame(codec_ctx, frame) == 0) - { - if (frame->pts >= target_pts) - { - found = YES; - break; - } - } - } - } - av_packet_unref(&pkt); - if (found) - { - break; - } - } - - av_frame_free(&frame); - return found; -} -*/ - // Ignore the warning this will produce as it is intentional. #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation" @@ -495,6 +441,17 @@ - (BOOL) isMuted // NSMovieView subclass that does all of the actual work of decoding... @implementation GSMovieView ++ (void) initialize +{ + if (self == [GSMovieView class]) + { + if (nc == nil) + { + nc = [NSNotificationCenter defaultCenter]; + } + } +} + - (instancetype) initWithFrame: (NSRect)frame { self = [super initWithFrame: frame]; @@ -511,7 +468,12 @@ - (instancetype) initWithFrame: (NSRect)frame _videoCodecCtx = NULL; _formatCtx = NULL; _swsCtx = NULL; - _lastPts = 0; + _lastPts = 0; + // NSApplicationWillTerminateNotification + [nc addObserver: self + selector: @selector(handleNotification:) + name: NSApplicationWillTerminateNotification + object: nil]; } return self; } @@ -544,39 +506,29 @@ - (void)dealloc TEST_RELEASE(_currentFrame); DESTROY(_videoPackets); DESTROY(_audioPlayer); + [nc removeObserver: self]; [super dealloc]; } -// Private methods... -- (void) _resetFeed +// Notification responses... +- (void) handleNotification: (NSNotification *)notification { - [self stop: nil]; - [self start: nil]; + NSLog(@"[GSMovieView] Shutting down, final pts %ld", _lastPts); + + [_feedThread cancel]; + [_videoThread cancel]; + [_audioPlayer stopAudio]; + [self stopVideo]; } -/* -- (void) _gotoFrame: (int64_t)pts +// Private methods... +- (void) _resetFeed: (int64_t)pts { - BOOL success = [self reset]; - - if(success) - { - success = seek_to_pts(_formatCtx, - _videoCodecCtx, - _videoStreamIndex, - _lastPts); - if (!success) - { - NSLog(@"Failed to seek to frame"); - } - } - else - { - NSLog(@"Failed to reset frame"); - } + [self stop: nil]; + _savedPts = pts; + // [self start: nil]; } -*/ // Overridden methods from the superclass... - (BOOL) isPlaying @@ -666,15 +618,13 @@ - (NSRect) movieRect - (IBAction)gotoPosterFrame: (id)sender { - _savedPts = 0.0; - [self _resetFeed]; + [self _resetFeed: _savedPts]; NSLog(@"[GSMovieView] gotoPosterFrame called | Timestamp: %ld", av_gettime()); } - (IBAction)gotoBeginning: (id)sender { - _savedPts = 0.0; - [self _resetFeed]; + [self _resetFeed: _savedPts]; NSLog(@"[GSMovieView] gotoBeginning called | Timestamp: %ld", av_gettime()); } @@ -774,7 +724,6 @@ - (void) feedVideo return; } - // NSLog(@"_formatCtx = %lld", _formatCtx); if (avformat_find_stream_info(_formatCtx, NULL) < 0) { NSLog(@"[Error] Could not find stream info. | Timestamp: %ld", av_gettime()); @@ -832,53 +781,47 @@ - (void) feedVideo return; } - // Seek to the current PTS... - BOOL success = YES; + AVPacket packet; + int64_t i = 0; - // seek_to_pts(_formatCtx, - // _videoCodecCtx, - // _videoStreamIndex, - // _lastPts); - - if (success) + while (av_read_frame(_formatCtx, &packet) >= 0) { - AVPacket packet; - int64_t i = 0; - - while (av_read_frame(_formatCtx, &packet) >= 0) + if (packet.pts <= _savedPts) { - // After 1000 frames, start the thread... - if (i == 1000) - { - [self startVideo]; - [_audioPlayer startAudio]; - } - - if (packet.stream_index == _videoStreamIndex) - { - [self submitVideoPacket: &packet]; - } - - if (packet.stream_index == _audioStreamIndex) - { - [_audioPlayer submitPacket: &packet]; - } - - av_packet_unref(&packet); - i++; + continue; } - - // if we had a very short video... play it. - if (i < 1000) + + // After 1000 frames, start the thread... + if (i == 1000) { - NSLog(@"[GSMovieView] Starting short video... | Timestamp: %ld", av_gettime()); [self startVideo]; [_audioPlayer startAudio]; } + + if (packet.stream_index == _videoStreamIndex) + { + [self submitVideoPacket: &packet]; + } + + if (packet.stream_index == _audioStreamIndex) + { + [_audioPlayer submitPacket: &packet]; + } + + av_packet_unref(&packet); + i++; + } + + // if we had a very short video... play it. + if (i < 1000) + { + NSLog(@"[GSMovieView] Starting short video... | Timestamp: %ld", av_gettime()); + [self startVideo]; + [_audioPlayer startAudio]; } - - avformat_close_input(&_formatCtx); } + + avformat_close_input(&_formatCtx); } } @@ -1011,6 +954,8 @@ - (void)videoThreadEntry int64_t delay = packetTime - now; // Show the information... + _statusString = [NSString stringWithFormat: @"[GSMovieView] Rendering video frame PTS: %ld | Delay: %ld us", + packet.pts, delay]; fprintf(stderr, "[GSMovieView] Rendering video frame PTS: %ld | Delay: %ld us\r", packet.pts, delay); if (delay > 0) @@ -1085,4 +1030,9 @@ - (void)decodeVideoPacket: (AVPacket *)packet } } +- (NSString *) statusString +{ + return _statusString; +} + @end From e467716a8a18c5afbaaa2e12410386ec35305306 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Sat, 7 Jun 2025 05:49:06 -0400 Subject: [PATCH 49/86] Add TextField so that status can be shown. This is a GS extension --- Headers/AppKit/NSMovieView.h | 11 +++++++++++ Source/GSMovieView.m | 7 +++++++ Source/NSMovieView.m | 13 +++++++++++++ 3 files changed, 31 insertions(+) diff --git a/Headers/AppKit/NSMovieView.h b/Headers/AppKit/NSMovieView.h index 471463e37d..d7e51469df 100644 --- a/Headers/AppKit/NSMovieView.h +++ b/Headers/AppKit/NSMovieView.h @@ -35,6 +35,7 @@ #import #import +@class NSTextField; @class NSMovie; typedef enum { @@ -46,7 +47,9 @@ typedef enum { APPKIT_EXPORT_CLASS @interface NSMovieView : NSView { + IBOutlet NSTextField *_statusField; NSMovie* _movie; + float _rate; float _volume; BOOL _playing; @@ -241,6 +244,14 @@ APPKIT_EXPORT_CLASS */ - (IBAction) selectAll: (id)sender; +/** + * GNUstep extension, this allows the user to set a + * text field to monitor the status of the movie view. + * +- (void) setStatusField: (id)field; +- (id) statusField; +*/ + @end #endif /* _GNUstep_H_NSMovieView */ diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 3a4ddf2912..52920a32c3 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -956,6 +956,13 @@ - (void)videoThreadEntry // Show the information... _statusString = [NSString stringWithFormat: @"[GSMovieView] Rendering video frame PTS: %ld | Delay: %ld us", packet.pts, delay]; + NSLog(@"statusField = %@", _statusField); + if (_statusField != nil) + { + NSLog(@"Setting..."); + [_statusField setStringValue: _statusString]; + } + fprintf(stderr, "[GSMovieView] Rendering video frame PTS: %ld | Delay: %ld us\r", packet.pts, delay); if (delay > 0) diff --git a/Source/NSMovieView.m b/Source/NSMovieView.m index 22c7ccab71..84ce91060a 100644 --- a/Source/NSMovieView.m +++ b/Source/NSMovieView.m @@ -252,4 +252,17 @@ - (IBAction) selectAll: (id)sender { } +// GNUstep extension... +/* +- (void) setStatusField: (NSTextField *)field +{ + ASSIGN(_statusField, field); +} + +- (NSTextField *) statusField +{ + return _statusField; +} +*/ + @end From cc24648d20ded1bf0c07bfa414cdd77faea2b1ba Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Sat, 7 Jun 2025 06:18:00 -0400 Subject: [PATCH 50/86] Add support for status field --- Source/GSMovieView.m | 13 +++---------- Source/NSMovieView.m | 13 ------------- 2 files changed, 3 insertions(+), 23 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 52920a32c3..b2103ef1bd 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -953,13 +953,11 @@ - (void)videoThreadEntry int64_t now = av_gettime() - _videoClock; int64_t delay = packetTime - now; - // Show the information... - _statusString = [NSString stringWithFormat: @"[GSMovieView] Rendering video frame PTS: %ld | Delay: %ld us", - packet.pts, delay]; - NSLog(@"statusField = %@", _statusField); if (_statusField != nil) { - NSLog(@"Setting..."); + // Show the information... + _statusString = [NSString stringWithFormat: @"Rendering video frame PTS: %ld | Delay: %ld us | %@", + packet.pts, delay, _running ? @"Running" : @"Stopped"]; [_statusField setStringValue: _statusString]; } @@ -1037,9 +1035,4 @@ - (void)decodeVideoPacket: (AVPacket *)packet } } -- (NSString *) statusString -{ - return _statusString; -} - @end diff --git a/Source/NSMovieView.m b/Source/NSMovieView.m index 84ce91060a..22c7ccab71 100644 --- a/Source/NSMovieView.m +++ b/Source/NSMovieView.m @@ -252,17 +252,4 @@ - (IBAction) selectAll: (id)sender { } -// GNUstep extension... -/* -- (void) setStatusField: (NSTextField *)field -{ - ASSIGN(_statusField, field); -} - -- (NSTextField *) statusField -{ - return _statusField; -} -*/ - @end From dff017a349bb0615a618c0cccebb5e799e9f05a2 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Sat, 7 Jun 2025 14:37:11 -0400 Subject: [PATCH 51/86] Skip any corrupt packets --- Source/GSMovieView.m | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index b2103ef1bd..84edb8f653 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -341,11 +341,21 @@ - (void)audioThreadEntry - (void)decodeAudioPacket: (AVPacket *)packet { if (!_audioCodecCtx || !_swrCtx || !_aoDev) - return; - + { + return; + } + if (avcodec_send_packet(_audioCodecCtx, packet) < 0) - return; - + { + return; + } + + if (packet->flags & AV_PKT_FLAG_CORRUPT) + { + NSLog(@"Skipping corrupt audio packet"); + return; + } + while (avcodec_receive_frame(_audioCodecCtx, _audioFrame) == 0) { int outSamples = _audioFrame->nb_samples; @@ -986,11 +996,21 @@ - (void)videoThreadEntry - (void)decodeVideoPacket: (AVPacket *)packet { if (!_videoCodecCtx || !_swsCtx) - return; + { + return; + } if (avcodec_send_packet(_videoCodecCtx, packet) < 0) - return; - + { + return; + } + + if (packet->flags & AV_PKT_FLAG_CORRUPT) + { + NSLog(@"Skipping corrupt video packet"); + return; + } + _lastPts = packet->pts; while (avcodec_receive_frame(_videoCodecCtx, _videoFrame) == 0) From 08c88d653cee155ca5c2602029d727e0654f5b9e Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Sun, 8 Jun 2025 04:54:47 -0400 Subject: [PATCH 52/86] Add renderFrame: method --- Source/GSMovieView.h | 1 + Source/GSMovieView.m | 147 +++++++++++++++++++++---------------------- 2 files changed, 71 insertions(+), 77 deletions(-) diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index 9f447a5585..84c3492a6c 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -86,6 +86,7 @@ APPKIT_EXPORT_CLASS - (void) stopVideo; // Main loop to process packets... +- (void) renderFrame: (AVFrame *)videoFrame; - (void) feedVideo; @end diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 84edb8f653..ae4db173b8 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -640,53 +640,40 @@ - (IBAction)gotoBeginning: (id)sender - (IBAction)gotoEnd: (id)sender { - AVFormatContext *fmt_ctx = NULL; - NSURL *url = [[self movie] URL]; - const char *name = [[url path] UTF8String]; + NSLog(@"_videoStreamIndex = %d", _videoStreamIndex); + AVStream *videoStream = _formatCtx->streams[_videoStreamIndex]; + int64_t duration = videoStream->duration; + // AVRational timeBase = videoStream->time_base; - NSLog(@"Stopping..."); [self stop: nil]; + + // Seek near the end (some formats don't like seeking to exact end) + int64_t seekTarget = duration - (AV_TIME_BASE / 10); // a bit before the end + av_seek_frame(_formatCtx, _videoStreamIndex, seekTarget, AVSEEK_FLAG_BACKWARD); - // Open video file - NSLog(@"Name... %s", name); - avformat_open_input(&fmt_ctx, name, NULL, NULL); - - // Find the first video stream - int video_stream_index = -1; - unsigned int i = 0; - for (i = 0; i < fmt_ctx->nb_streams; i++) - { - if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) - { - video_stream_index = i; - break; - } - } + // Flush decoder + avcodec_flush_buffers(_videoCodecCtx); - NSLog(@"stream = %d", video_stream_index); - // Find and decode the packet - AVPacket pkt; - int64_t last_pts = AV_NOPTS_VALUE; - av_seek_frame(fmt_ctx, video_stream_index, INT64_MAX, AVSEEK_FLAG_BACKWARD); - while (av_read_frame(fmt_ctx, &pkt) >= 0) + // Read packets and decode + AVPacket packet; + while (av_read_frame(_formatCtx, &packet) >= 0) { - if (pkt.stream_index == video_stream_index) + if (packet.stream_index == _videoStreamIndex) { - if (pkt.pts != AV_NOPTS_VALUE) + if (avcodec_send_packet(_videoCodecCtx, &packet) == 0) { - last_pts = pkt.pts; + AVFrame *frame = av_frame_alloc(); + if (avcodec_receive_frame(_videoCodecCtx, frame) == 0) + { + // Convert & render this frame + [self renderFrame: frame]; + av_frame_free(&frame); + break; + } + av_frame_free(&frame); } } - av_packet_unref(&pkt); - } - - NSLog(@"last_pts = %ld", last_pts); - - if (last_pts != AV_NOPTS_VALUE) - { - double seconds = last_pts * av_q2d(fmt_ctx->streams[video_stream_index]->time_base); - // [self _gotoFrame: last_pts]; - NSLog(@"Last decoded PTS: %" PRId64 " (%.3f sec)\n", last_pts, seconds); + av_packet_unref(&packet); } } @@ -970,7 +957,8 @@ - (void)videoThreadEntry packet.pts, delay, _running ? @"Running" : @"Stopped"]; [_statusField setStringValue: _statusString]; } - + + // Show status on the command line... fprintf(stderr, "[GSMovieView] Rendering video frame PTS: %ld | Delay: %ld us\r", packet.pts, delay); if (delay > 0) @@ -993,7 +981,48 @@ - (void)videoThreadEntry } } -- (void)decodeVideoPacket: (AVPacket *)packet +- (void) renderFrame: (AVFrame *)videoFrame +{ + uint8_t *rgbData[1]; + int rgbLineSize[1]; + int width = _videoCodecCtx->width; + int height = _videoCodecCtx->height; + + rgbLineSize[0] = width * 3; + rgbData[0] = (uint8_t *)malloc(height * rgbLineSize[0]); + + sws_scale(_swsCtx, + (const uint8_t * const *)videoFrame->data, + videoFrame->linesize, + 0, + height, + rgbData, + rgbLineSize); + + NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] + initWithBitmapDataPlanes: &rgbData[0] + pixelsWide: width + pixelsHigh: height + bitsPerSample: 8 + samplesPerPixel: 3 + hasAlpha: NO + isPlanar: NO + colorSpaceName: NSCalibratedRGBColorSpace + bytesPerRow: rgbLineSize[0] + bitsPerPixel: 24]; + + NSImage *image = [[NSImage alloc] initWithSize: NSMakeSize(width, height)]; + [image addRepresentation: bitmap]; + [self performSelectorOnMainThread: @selector(updateImage:) + withObject: image + waitUntilDone: NO]; + + RELEASE(image); + RELEASE(bitmap); + free(rgbData[0]); +} + +- (void) decodeVideoPacket: (AVPacket *)packet { if (!_videoCodecCtx || !_swsCtx) { @@ -1015,43 +1044,7 @@ - (void)decodeVideoPacket: (AVPacket *)packet while (avcodec_receive_frame(_videoCodecCtx, _videoFrame) == 0) { - uint8_t *rgbData[1]; - int rgbLineSize[1]; - int width = _videoCodecCtx->width; - int height = _videoCodecCtx->height; - - rgbLineSize[0] = width * 3; - rgbData[0] = (uint8_t *)malloc(height * rgbLineSize[0]); - - sws_scale(_swsCtx, - (const uint8_t * const *)_videoFrame->data, - _videoFrame->linesize, - 0, - height, - rgbData, - rgbLineSize); - - NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] - initWithBitmapDataPlanes: &rgbData[0] - pixelsWide: width - pixelsHigh: height - bitsPerSample: 8 - samplesPerPixel: 3 - hasAlpha: NO - isPlanar: NO - colorSpaceName: NSCalibratedRGBColorSpace - bytesPerRow: rgbLineSize[0] - bitsPerPixel: 24]; - - NSImage *image = [[NSImage alloc] initWithSize: NSMakeSize(width, height)]; - [image addRepresentation: bitmap]; - [self performSelectorOnMainThread: @selector(updateImage:) - withObject: image - waitUntilDone: NO]; - - RELEASE(image); - RELEASE(bitmap); - free(rgbData[0]); + [self renderFrame: _videoFrame]; } } From e33949459b08e80b34a690a8e4cf3b16ba479dca Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Sun, 8 Jun 2025 05:00:28 -0400 Subject: [PATCH 53/86] Add renderFrame: method --- Source/GSMovieView.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index ae4db173b8..0c5f0dfec0 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -1034,12 +1034,13 @@ - (void) decodeVideoPacket: (AVPacket *)packet return; } - if (packet->flags & AV_PKT_FLAG_CORRUPT) + if (packet->flags & AV_PKT_FLAG_CORRUPT) { NSLog(@"Skipping corrupt video packet"); return; } + // Record last pts... _lastPts = packet->pts; while (avcodec_receive_frame(_videoCodecCtx, _videoFrame) == 0) From 03f591cf2e2e5a4a3097a991539e3ebb0213b154 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Sun, 8 Jun 2025 17:52:02 -0400 Subject: [PATCH 54/86] Separate concerns into different methods so that setup, loop, and close are handled discretely --- Source/GSMovieView.h | 3 + Source/GSMovieView.m | 135 +++++++++++++++++++++++++++---------------- 2 files changed, 87 insertions(+), 51 deletions(-) diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index 84c3492a6c..0d5bdc5c80 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -88,6 +88,9 @@ APPKIT_EXPORT_CLASS // Main loop to process packets... - (void) renderFrame: (AVFrame *)videoFrame; - (void) feedVideo; +- (BOOL) setup; +- (void) loop; +- (void) close; @end diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 0c5f0dfec0..681c93a656 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -533,12 +533,19 @@ - (void) handleNotification: (NSNotification *)notification } // Private methods... -- (void) _resetFeed: (int64_t)pts +- (void) _startAtPts: (int64_t)pts { - [self stop: nil]; - _savedPts = pts; - // [self start: nil]; -} + if (_running == NO) + { + [self setRate: 1.0 / 30.0]; + [self setVolume: 1.0]; + + _savedPts = pts; + _feedThread = [[NSThread alloc] initWithTarget:self selector:@selector(feedVideo) object:nil]; + [_feedThread start]; + [_audioPlayer startAudio]; + } +} // Overridden methods from the superclass... - (BOOL) isPlaying @@ -548,15 +555,7 @@ - (BOOL) isPlaying - (IBAction) start: (id)sender { - if (_running == NO) - { - [self setRate: 1.0 / 30.0]; - [self setVolume: 1.0]; - - _feedThread = [[NSThread alloc] initWithTarget:self selector:@selector(feedVideo) object:nil]; - [_feedThread start]; - [_audioPlayer startAudio]; - } + [self _startAtPts: 0]; } - (IBAction) stop: (id)sender @@ -628,13 +627,15 @@ - (NSRect) movieRect - (IBAction)gotoPosterFrame: (id)sender { - [self _resetFeed: _savedPts]; + [self stop: sender]; + [self _startAtPts: 0]; NSLog(@"[GSMovieView] gotoPosterFrame called | Timestamp: %ld", av_gettime()); } - (IBAction)gotoBeginning: (id)sender { - [self _resetFeed: _savedPts]; + [self stop: sender]; + [self _startAtPts: 0]; NSLog(@"[GSMovieView] gotoBeginning called | Timestamp: %ld", av_gettime()); } @@ -679,10 +680,14 @@ - (IBAction)gotoEnd: (id)sender - (IBAction) stepForward: (id)sender { + [self stop: sender]; + [self _startAtPts: _savedPts + 1000]; } - (IBAction) stepBack: (id)sender { + [self stop: sender]; + [self _startAtPts: _savedPts - 1000]; } // Video playback methods... @@ -701,7 +706,7 @@ - (void) drawRect: (NSRect)dirtyRect } } -- (void) feedVideo +- (BOOL) setup { NSMovie *movie = [self movie]; @@ -718,14 +723,14 @@ - (void) feedVideo if (avformat_open_input(&_formatCtx, path, NULL, NULL) != 0) { NSLog(@"[Error] Could not open file: %s | Timestamp: %ld", path, av_gettime()); - return; + return NO; } if (avformat_find_stream_info(_formatCtx, NULL) < 0) { NSLog(@"[Error] Could not find stream info. | Timestamp: %ld", av_gettime()); avformat_close_input(&_formatCtx); - return; + return NO; } _videoStreamIndex = -1; @@ -775,53 +780,81 @@ - (void) feedVideo { NSLog(@"[Error] No video or audio stream detected, exiting"); avformat_close_input(&_formatCtx); - return; + return NO; } + } + } + + return YES; +} - AVPacket packet; - int64_t i = 0; +- (void) loop +{ + if (_formatCtx != NULL) + { + AVPacket packet; + int64_t i = 0; - while (av_read_frame(_formatCtx, &packet) >= 0) + while (av_read_frame(_formatCtx, &packet) >= 0) + { + if (packet.pts <= _savedPts) { - if (packet.pts <= _savedPts) - { - continue; - } + continue; + } - // After 1000 frames, start the thread... - if (i == 1000) - { - [self startVideo]; - [_audioPlayer startAudio]; - } + // After 1000 frames, start the thread... + if (i == 1000) + { + [self startVideo]; + [_audioPlayer startAudio]; + } - if (packet.stream_index == _videoStreamIndex) - { - [self submitVideoPacket: &packet]; - } - - if (packet.stream_index == _audioStreamIndex) - { - [_audioPlayer submitPacket: &packet]; - } - - av_packet_unref(&packet); - i++; + if (packet.stream_index == _videoStreamIndex) + { + [self submitVideoPacket: &packet]; } - // if we had a very short video... play it. - if (i < 1000) + if (packet.stream_index == _audioStreamIndex) { - NSLog(@"[GSMovieView] Starting short video... | Timestamp: %ld", av_gettime()); - [self startVideo]; - [_audioPlayer startAudio]; + [_audioPlayer submitPacket: &packet]; } + + av_packet_unref(&packet); + i++; } - + + // if we had a very short video... play it. + if (i < 1000) + { + NSLog(@"[GSMovieView] Starting short video... | Timestamp: %ld", av_gettime()); + [self startVideo]; + [_audioPlayer startAudio]; + } + } +} + +- (void) close +{ + if (_formatCtx != NULL) + { avformat_close_input(&_formatCtx); } } +- (void) feedVideo +{ + BOOL success = [self setup]; + if (success) + { + [self loop]; + [self close]; + } + else + { + NSLog(@"[GSMovieView] setup failed."); + } +} + - (void)prepareVideoWithFormatContext: (AVFormatContext *)formatCtx streamIndex: (int)videoStreamIndex { AVCodecParameters *videoPar = formatCtx->streams[videoStreamIndex]->codecpar; From 79ba3c71563261d87a5c44e41a44d23bbd94c412 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 9 Jun 2025 12:58:18 -0400 Subject: [PATCH 55/86] Add logic to skip forward --- Source/GSMovieView.m | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 681c93a656..e121a4348a 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -680,8 +680,11 @@ - (IBAction)gotoEnd: (id)sender - (IBAction) stepForward: (id)sender { - [self stop: sender]; - [self _startAtPts: _savedPts + 1000]; + AVStream *videoStream = _formatCtx->streams[_videoStreamIndex];s + int64_t skip = av_rescale_q(seconds, (AVRational){1,1}, videoStream->time_base); + int64_t newPts = lastDecodedPTS + skip; + av_seek_frame(fmtCtx, videoStreamIndex, newPts, AVSEEK_FLAG_BACKWARD); + avcodec_flush_buffers(codecCtx); } - (IBAction) stepBack: (id)sender From 3f499294126ff8522342d25eb5e4d06104db782b Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 9 Jun 2025 13:45:50 -0400 Subject: [PATCH 56/86] Cleanup, and cache stream --- Source/GSMovieView.h | 3 ++- Source/GSMovieView.m | 17 ++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index 0d5bdc5c80..6bf01d9f65 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -55,12 +55,13 @@ APPKIT_EXPORT_CLASS NSThread *_videoThread; NSThread *_feedThread; NSImage *_currentFrame; - GSAudioPlayer *_audioPlayer; NSString *_statusString; + GSAudioPlayer *_audioPlayer; AVCodecContext *_videoCodecCtx; AVFrame *_videoFrame; AVFormatContext *_formatCtx; + AVStream *_stream; struct SwsContext *_swsCtx; AVRational _timeBase; diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index e121a4348a..87e6dcb7f5 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -478,6 +478,7 @@ - (instancetype) initWithFrame: (NSRect)frame _videoCodecCtx = NULL; _formatCtx = NULL; _swsCtx = NULL; + _stream = NULL; _lastPts = 0; // NSApplicationWillTerminateNotification [nc addObserver: self @@ -641,10 +642,7 @@ - (IBAction)gotoBeginning: (id)sender - (IBAction)gotoEnd: (id)sender { - NSLog(@"_videoStreamIndex = %d", _videoStreamIndex); - AVStream *videoStream = _formatCtx->streams[_videoStreamIndex]; - int64_t duration = videoStream->duration; - // AVRational timeBase = videoStream->time_base; + int64_t duration = _stream->duration; [self stop: nil]; @@ -680,11 +678,11 @@ - (IBAction)gotoEnd: (id)sender - (IBAction) stepForward: (id)sender { - AVStream *videoStream = _formatCtx->streams[_videoStreamIndex];s - int64_t skip = av_rescale_q(seconds, (AVRational){1,1}, videoStream->time_base); - int64_t newPts = lastDecodedPTS + skip; - av_seek_frame(fmtCtx, videoStreamIndex, newPts, AVSEEK_FLAG_BACKWARD); - avcodec_flush_buffers(codecCtx); + int64_t seconds = 2; + int64_t skip = av_rescale_q(seconds, (AVRational){1,1}, _stream->time_base); + int64_t newPts = _lastPts + skip; + av_seek_frame(_formatCtx, _videoStreamIndex, newPts, AVSEEK_FLAG_BACKWARD); + avcodec_flush_buffers(_videoCodecCtx); } - (IBAction) stepBack: (id)sender @@ -741,6 +739,7 @@ - (BOOL) setup { if (_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { + _stream = _formatCtx->streams[i]; _videoStreamIndex = i; break; } From c92347e5fb5ab4bd40f6c123ded855078bdec734 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Tue, 10 Jun 2025 02:16:31 -0400 Subject: [PATCH 57/86] Initial changes for pause --- Source/GSMovieView.h | 8 +- Source/GSMovieView.m | 302 ++++++++++++++++++++++--------------------- 2 files changed, 160 insertions(+), 150 deletions(-) diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index 6bf01d9f65..fca5f7d818 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -65,8 +65,9 @@ APPKIT_EXPORT_CLASS struct SwsContext *_swsCtx; AVRational _timeBase; - BOOL _running; - BOOL _started; + BOOL _paused; // is the stream paused... + BOOL _running; // is the loop currently running... + BOOL _started; // has the video started... int64_t _videoClock; int _videoStreamIndex; int _audioStreamIndex; @@ -76,7 +77,7 @@ APPKIT_EXPORT_CLASS // Initialization... - (void) prepareVideoWithFormatContext: (AVFormatContext *)formatCtx - streamIndex: (int)videoStreamIndex; + streamIndex: (int)videoStreamIndex; // Submit packets... - (void) submitVideoPacket: (AVPacket *)packet; @@ -85,6 +86,7 @@ APPKIT_EXPORT_CLASS // Start and stop... - (void) startVideo; - (void) stopVideo; +- (void) setPlaying: (BOOL)f; // Main loop to process packets... - (void) renderFrame: (AVFrame *)videoFrame; diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 87e6dcb7f5..0da4928dac 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -148,10 +148,10 @@ @interface GSAudioPlayer : NSObject int64_t _audioClock; AVRational _timeBase; BOOL _running; - float _volume; /* 0.0 to 1.0 */ BOOL _started; - unsigned int _loopMode:3; BOOL _muted; + float _volume; /* 0.0 to 1.0 */ + unsigned int _loopMode:3; NSMutableArray *_audioPackets; NSThread *_audioThread; @@ -172,6 +172,8 @@ - (void) setLoopMode: (NSQTMovieLoopMode)mode; - (BOOL) isMuted; - (void) setMuted: (BOOL)muted; +- (void) setPlaying: (BOOL)f; + @end @implementation GSAudioPlayer @@ -224,6 +226,16 @@ - (void)dealloc [super dealloc]; } +- (void) setPlaying: (BOOL)f +{ + _running = f; +} + +- (BOOL) isPlaying +{ + return _running; +} + - (NSQTMovieLoopMode) loopMode { return _loopMode; @@ -296,7 +308,7 @@ - (void)audioThreadEntry CREATE_AUTORELEASE_POOL(pool); { NSDictionary *dict = nil; - + @synchronized (_audioPackets) { if (!_started && [_audioPackets count] < 5) @@ -304,19 +316,20 @@ - (void)audioThreadEntry usleep(5000); continue; } + if ([_audioPackets count] > 0) { dict = [[_audioPackets objectAtIndex:0] retain]; [_audioPackets removeObjectAtIndex:0]; } } - + if (!_started && dict) { _audioClock = av_gettime(); _started = YES; } - + if (dict) { AVPacket packet = AVPacketFromNSDictionary(dict); @@ -325,7 +338,7 @@ - (void)audioThreadEntry int64_t delay = packetTime - now; if (delay > 0) usleep((useconds_t)delay); - + [self decodeAudioPacket:&packet]; [dict release]; } @@ -344,18 +357,18 @@ - (void)decodeAudioPacket: (AVPacket *)packet { return; } - + if (avcodec_send_packet(_audioCodecCtx, packet) < 0) { return; } - + if (packet->flags & AV_PKT_FLAG_CORRUPT) { NSLog(@"Skipping corrupt audio packet"); return; } - + while (avcodec_receive_frame(_audioCodecCtx, _audioFrame) == 0) { int outSamples = _audioFrame->nb_samples; @@ -398,6 +411,7 @@ - (void)submitPacket: (AVPacket *)packet - (void)startAudio { + _running = YES; NSLog(@"[GSMovieView] Starting audio thread | Timestamp: %ld", av_gettime()); _audioThread = [[NSThread alloc] initWithTarget:self selector:@selector(audioThreadEntry) object:nil]; [_audioThread start]; @@ -472,15 +486,19 @@ - (instancetype) initWithFrame: (NSRect)frame _feedThread = nil; _audioPlayer = [[GSAudioPlayer alloc] init]; _videoPackets = [[NSMutableArray alloc] init]; - _running = NO; - _started = NO; + + // AV _videoClock = 0; _videoCodecCtx = NULL; _formatCtx = NULL; _swsCtx = NULL; _stream = NULL; _lastPts = 0; - // NSApplicationWillTerminateNotification + + // Flags + _running = NO; + _started = NO; + [nc addObserver: self selector: @selector(handleNotification:) name: NSApplicationWillTerminateNotification @@ -526,7 +544,7 @@ - (void)dealloc - (void) handleNotification: (NSNotification *)notification { NSLog(@"[GSMovieView] Shutting down, final pts %ld", _lastPts); - + [_feedThread cancel]; [_videoThread cancel]; [_audioPlayer stopAudio]; @@ -534,19 +552,29 @@ - (void) handleNotification: (NSNotification *)notification } // Private methods... -- (void) _startAtPts: (int64_t)pts +- (void) _startFeed { if (_running == NO) { [self setRate: 1.0 / 30.0]; [self setVolume: 1.0]; - - _savedPts = pts; + + _savedPts = 0; _feedThread = [[NSThread alloc] initWithTarget:self selector:@selector(feedVideo) object:nil]; [_feedThread start]; [_audioPlayer startAudio]; } -} +} + +- (void) _stopFeed +{ + if (_running == YES) + { + _savedPts = _lastPts; + [_feedThread cancel]; + [_audioPlayer stopAudio]; + } +} // Overridden methods from the superclass... - (BOOL) isPlaying @@ -556,19 +584,12 @@ - (BOOL) isPlaying - (IBAction) start: (id)sender { - [self _startAtPts: 0]; + [self setPlaying: YES]; } - (IBAction) stop: (id)sender { - if (_running) - { - [_feedThread cancel]; - [self stopVideo]; - [_audioPlayer stopAudio]; - - DESTROY(_feedThread); - } + [self setPlaying: NO]; } - (void) setMuted: (BOOL)muted @@ -588,6 +609,15 @@ - (void) setLoopMode: (NSQTMovieLoopMode)mode [super setLoopMode: mode]; } +- (void) setMovie: (NSMovie *)movie +{ + @synchronized(_movie) + { + [super setMovie: movie]; + [self _startFeed]; + } +} + - (NSRect) movieRect { AVFormatContext* fmt_ctx = NULL; @@ -598,7 +628,7 @@ - (NSRect) movieRect // which occurs when setting this from the existing stream. // The issue with using the ivars is that they are initialized on // a thread, so they may not be set when this is called. - + // Open video file avformat_open_input(&fmt_ctx, name, NULL, NULL); avformat_find_stream_info(fmt_ctx, NULL); @@ -629,51 +659,20 @@ - (NSRect) movieRect - (IBAction)gotoPosterFrame: (id)sender { [self stop: sender]; - [self _startAtPts: 0]; + // [self _startAtPts: 0]; NSLog(@"[GSMovieView] gotoPosterFrame called | Timestamp: %ld", av_gettime()); } - (IBAction)gotoBeginning: (id)sender { [self stop: sender]; - [self _startAtPts: 0]; + // [self _startAtPts: 0]; NSLog(@"[GSMovieView] gotoBeginning called | Timestamp: %ld", av_gettime()); } - (IBAction)gotoEnd: (id)sender { - int64_t duration = _stream->duration; - - [self stop: nil]; - - // Seek near the end (some formats don't like seeking to exact end) - int64_t seekTarget = duration - (AV_TIME_BASE / 10); // a bit before the end - av_seek_frame(_formatCtx, _videoStreamIndex, seekTarget, AVSEEK_FLAG_BACKWARD); - - // Flush decoder - avcodec_flush_buffers(_videoCodecCtx); - - // Read packets and decode - AVPacket packet; - while (av_read_frame(_formatCtx, &packet) >= 0) - { - if (packet.stream_index == _videoStreamIndex) - { - if (avcodec_send_packet(_videoCodecCtx, &packet) == 0) - { - AVFrame *frame = av_frame_alloc(); - if (avcodec_receive_frame(_videoCodecCtx, frame) == 0) - { - // Convert & render this frame - [self renderFrame: frame]; - av_frame_free(&frame); - break; - } - av_frame_free(&frame); - } - } - av_packet_unref(&packet); - } + // } - (IBAction) stepForward: (id)sender @@ -688,7 +687,7 @@ - (IBAction) stepForward: (id)sender - (IBAction) stepBack: (id)sender { [self stop: sender]; - [self _startAtPts: _savedPts - 1000]; + // [self _startAtPts: _savedPts - 1000]; } // Video playback methods... @@ -793,7 +792,7 @@ - (BOOL) setup - (void) loop { if (_formatCtx != NULL) - { + { AVPacket packet; int64_t i = 0; @@ -803,14 +802,14 @@ - (void) loop { continue; } - + // After 1000 frames, start the thread... if (i == 1000) { [self startVideo]; [_audioPlayer startAudio]; } - + if (packet.stream_index == _videoStreamIndex) { [self submitVideoPacket: &packet]; @@ -898,18 +897,22 @@ - (void)prepareVideoWithFormatContext: (AVFormatContext *)formatCtx streamIndex: - (void) startVideo { - NSLog(@"[GSMovieView] Starting video thread | Timestamp: %ld, lastPts = %ld", av_gettime(), _lastPts); + NSLog(@"[GSMovieView] Starting video thread | Timestamp: %ld, lastPts = %ld", + av_gettime(), _lastPts); if (!_running) { _running = YES; - _videoThread = [[NSThread alloc] initWithTarget:self selector:@selector(videoThreadEntry) object:nil]; + _videoThread = [[NSThread alloc] initWithTarget:self + selector:@selector(videoThreadEntry) + object:nil]; [_videoThread start]; } } - (void) stopVideo { - NSLog(@"[GSMovieView] Stopping video thread | Timestamp: %ld, lastPts = %ld", av_gettime(), _lastPts); + NSLog(@"[GSMovieView] Stopping video thread | Timestamp: %ld, lastPts = %ld", + av_gettime(), _lastPts); if (_running) { _running = NO; @@ -919,7 +922,7 @@ - (void) stopVideo { usleep(1000); } - + DESTROY(_videoThread); avformat_close_input(&_formatCtx); @@ -928,6 +931,12 @@ - (void) stopVideo } } +- (void) setPlaying: (BOOL)f +{ + _running = f; + [_audioPlayer setPlaying: _running]; +} + - (void)submitVideoPacket: (AVPacket *)packet { NSDictionary *dict = NSDictionaryFromAVPacket(packet); @@ -942,77 +951,76 @@ - (void)videoThreadEntry while (_running) { CREATE_AUTORELEASE_POOL(pool); - { - NSDictionary *dict = nil; - - // Pop the video packet off _videoPackets, sync on - // the array. - @synchronized (_videoPackets) - { - if (!_started && [_videoPackets count] < 3) - { - usleep(5000); - RELEASE(pool); - continue; - } - if ([_videoPackets count] > 0) - { - dict = RETAIN([_videoPackets objectAtIndex: 0]); - [_videoPackets removeObjectAtIndex: 0]; - } - } - - // If the dict is present and the thread is started, get - // the clock. - if (!_started && dict) - { - _videoClock = av_gettime(); - _started = YES; - } - - // If dict is not nil, decode it and get the frame... - if (dict) - { - AVPacket packet = AVPacketFromNSDictionary(dict); + { + NSDictionary *dict = nil; - // If the current pts is at or after the saved, - // then alow it to be decoded and displayed... - if (packet.pts >= _savedPts) - { - int64_t packetTime = av_rescale_q(packet.pts, - _timeBase, - (AVRational){1, 1000000}); - int64_t now = av_gettime() - _videoClock; - int64_t delay = packetTime - now; - - if (_statusField != nil) - { - // Show the information... - _statusString = [NSString stringWithFormat: @"Rendering video frame PTS: %ld | Delay: %ld us | %@", - packet.pts, delay, _running ? @"Running" : @"Stopped"]; - [_statusField setStringValue: _statusString]; - } - - // Show status on the command line... - fprintf(stderr, "[GSMovieView] Rendering video frame PTS: %ld | Delay: %ld us\r", - packet.pts, delay); - if (delay > 0) - { - usleep((useconds_t)delay); - } - - // Decode the packet, display it and play the sound... - [self decodeVideoPacket: &packet]; - RELEASE(dict); - } - else - { - usleep(1000); - } - } - - RELEASE(pool); - } + // Pop the video packet off _videoPackets, sync on + // the array. + @synchronized (_videoPackets) + { + if (!_started && [_videoPackets count] < 3) + { + usleep(5000); + RELEASE(pool); + continue; + } + if ([_videoPackets count] > 0) + { + dict = RETAIN([_videoPackets objectAtIndex: 0]); + [_videoPackets removeObjectAtIndex: 0]; + } + } + + // If the dict is present and the thread is started, get + // the clock. + if (!_started && dict) + { + _videoClock = av_gettime(); + _started = YES; + } + + // If dict is not nil, decode it and get the frame... + if (dict) + { + AVPacket packet = AVPacketFromNSDictionary(dict); + + // If the current pts is at or after the saved, + // then alow it to be decoded and displayed... + if (packet.pts >= _savedPts) + { + int64_t packetTime = av_rescale_q(packet.pts, + _timeBase, + (AVRational){1, 1000000}); + int64_t now = av_gettime() - _videoClock; + int64_t delay = packetTime - now; + + if (_statusField != nil) + { + // Show the information... + _statusString = [NSString stringWithFormat: @"Rendering video frame PTS: %ld | Delay: %ld us | %@", + packet.pts, delay, _running ? @"Running" : @"Stopped"]; + [_statusField setStringValue: _statusString]; + } + + // Show status on the command line... + fprintf(stderr, "[GSMovieView] Rendering video frame PTS: %ld | Delay: %ld us\r", + packet.pts, delay); + if (delay > 0) + { + usleep((useconds_t)delay); + } + + // Decode the packet, display it and play the sound... + [self decodeVideoPacket: &packet]; + RELEASE(dict); + } + else + { + usleep(1000); + } + } + } + RELEASE(pool); } } @@ -1022,10 +1030,10 @@ - (void) renderFrame: (AVFrame *)videoFrame int rgbLineSize[1]; int width = _videoCodecCtx->width; int height = _videoCodecCtx->height; - + rgbLineSize[0] = width * 3; rgbData[0] = (uint8_t *)malloc(height * rgbLineSize[0]); - + sws_scale(_swsCtx, (const uint8_t * const *)videoFrame->data, videoFrame->linesize, @@ -1033,7 +1041,7 @@ - (void) renderFrame: (AVFrame *)videoFrame height, rgbData, rgbLineSize); - + NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: &rgbData[0] pixelsWide: width @@ -1045,13 +1053,13 @@ - (void) renderFrame: (AVFrame *)videoFrame colorSpaceName: NSCalibratedRGBColorSpace bytesPerRow: rgbLineSize[0] bitsPerPixel: 24]; - + NSImage *image = [[NSImage alloc] initWithSize: NSMakeSize(width, height)]; [image addRepresentation: bitmap]; [self performSelectorOnMainThread: @selector(updateImage:) withObject: image waitUntilDone: NO]; - + RELEASE(image); RELEASE(bitmap); free(rgbData[0]); @@ -1068,16 +1076,16 @@ - (void) decodeVideoPacket: (AVPacket *)packet { return; } - + if (packet->flags & AV_PKT_FLAG_CORRUPT) { NSLog(@"Skipping corrupt video packet"); return; } - + // Record last pts... _lastPts = packet->pts; - + while (avcodec_receive_frame(_videoCodecCtx, _videoFrame) == 0) { [self renderFrame: _videoFrame]; From cf8e6bedd512f08c18ced6ce1e9433341e8e2c29 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Tue, 10 Jun 2025 03:19:57 -0400 Subject: [PATCH 58/86] Add pause --- Source/GNUmakefile | 1 + Source/GSMovieView.h | 3 +- Source/GSMovieView.m | 81 ++++++++++++++++++++++---------------------- 3 files changed, 44 insertions(+), 41 deletions(-) diff --git a/Source/GNUmakefile b/Source/GNUmakefile index f6ea402528..9b79ff77c5 100644 --- a/Source/GNUmakefile +++ b/Source/GNUmakefile @@ -378,6 +378,7 @@ GSColorSliderCell.m ifeq ($(BUILD_MOVIE), yes) libgnustep-gui_OBJC_FILES += GSMovieView.m +libgnustep-gui_OBJC_FILES += GSAudioPlayer.m endif # Turn off NSMenuItem warning that NSMenuItem conforms to , diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index fca5f7d818..328f98ccf8 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -86,7 +86,8 @@ APPKIT_EXPORT_CLASS // Start and stop... - (void) startVideo; - (void) stopVideo; -- (void) setPlaying: (BOOL)f; +- (void) setPaused: (BOOL)f; +- (BOOL) isPaused; // Main loop to process packets... - (void) renderFrame: (AVFrame *)videoFrame; diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 0da4928dac..e5b87b3c94 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -45,6 +45,7 @@ #import "AppKit/NSSound.h" #import "GSMovieView.h" +#import "GSAudioPlayer.h" #include @@ -137,45 +138,6 @@ + (NSArray*) movieUnfilteredPasteboardTypes #pragma clang diagnostic pop -// Audio player for NSMovieView... -@interface GSAudioPlayer : NSObject -{ - AVCodecContext *_audioCodecCtx; - AVFrame *_audioFrame; - SwrContext *_swrCtx; - ao_device *_aoDev; - ao_sample_format _aoFmt; - int64_t _audioClock; - AVRational _timeBase; - BOOL _running; - BOOL _started; - BOOL _muted; - float _volume; /* 0.0 to 1.0 */ - unsigned int _loopMode:3; - - NSMutableArray *_audioPackets; - NSThread *_audioThread; -} - -- (void) prepareAudioWithFormatContext: (AVFormatContext *)formatCtx - streamIndex: (int)audioStreamIndex; -- (void) decodeAudioPacket: (AVPacket *)packet; -- (void) startAudio; -- (void) stopAudio; - -- (float) volume; -- (void) setVolume: (float)volume; - -- (NSQTMovieLoopMode) loopMode; -- (void) setLoopMode: (NSQTMovieLoopMode)mode; - -- (BOOL) isMuted; -- (void) setMuted: (BOOL)muted; - -- (void) setPlaying: (BOOL)f; - -@end - @implementation GSAudioPlayer - (instancetype) init { @@ -191,6 +153,7 @@ - (instancetype) init _running = NO; _volume = 1.0; _started = NO; + _paused = NO; _loopMode = NSQTMovieNormalPlayback; } return self; @@ -226,6 +189,16 @@ - (void)dealloc [super dealloc]; } +- (void) setPaused: (BOOL)f; +{ + _paused = f; +} + +- (BOOL) isPaused +{ + return _paused; +} + - (void) setPlaying: (BOOL)f { _running = f; @@ -305,6 +278,14 @@ - (void)audioThreadEntry { while (_running) { + // Stop reading packets while paused... + if (_paused == YES) + { + usleep(10000); // 10ms pause + continue; // start the loop again... + } + + // create pool... CREATE_AUTORELEASE_POOL(pool); { NSDictionary *dict = nil; @@ -498,7 +479,8 @@ - (instancetype) initWithFrame: (NSRect)frame // Flags _running = NO; _started = NO; - + _paused = NO; + [nc addObserver: self selector: @selector(handleNotification:) name: NSApplicationWillTerminateNotification @@ -540,6 +522,17 @@ - (void)dealloc [super dealloc]; } +// New methods... +- (void) setPaused: (BOOL)f +{ + _paused = f; +} + +- (BOOL) isPaused +{ + return _paused; +} + // Notification responses... - (void) handleNotification: (NSNotification *)notification { @@ -950,6 +943,14 @@ - (void)videoThreadEntry { while (_running) { + // Stop reading packets while paused... + if (_paused == YES) + { + usleep(10000); // 10ms pause + continue; // start the loop again... + } + + // Create pool... CREATE_AUTORELEASE_POOL(pool); { NSDictionary *dict = nil; From 0e6caac4e6c1df138cdf420f44a740270c6f622a Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Tue, 10 Jun 2025 03:41:52 -0400 Subject: [PATCH 59/86] Separate out audio player and utilities, update GNUmakefile --- Source/GNUmakefile | 1 + Source/GSAVUtils.h | 39 +++++ Source/GSAVUtils.m | 65 ++++++++ Source/GSAudioPlayer.h | 96 ++++++++++++ Source/GSAudioPlayer.m | 335 ++++++++++++++++++++++++++++++++++++++++ Source/GSMovieView.m | 340 +---------------------------------------- 6 files changed, 537 insertions(+), 339 deletions(-) create mode 100644 Source/GSAVUtils.h create mode 100644 Source/GSAVUtils.m create mode 100644 Source/GSAudioPlayer.h create mode 100644 Source/GSAudioPlayer.m diff --git a/Source/GNUmakefile b/Source/GNUmakefile index 9b79ff77c5..b8fad0d7c8 100644 --- a/Source/GNUmakefile +++ b/Source/GNUmakefile @@ -379,6 +379,7 @@ GSColorSliderCell.m ifeq ($(BUILD_MOVIE), yes) libgnustep-gui_OBJC_FILES += GSMovieView.m libgnustep-gui_OBJC_FILES += GSAudioPlayer.m +libgnustep-gui_OBJC_FILES += GSAVUtils.m endif # Turn off NSMenuItem warning that NSMenuItem conforms to , diff --git a/Source/GSAVUtils.h b/Source/GSAVUtils.h new file mode 100644 index 0000000000..a251def3dd --- /dev/null +++ b/Source/GSAVUtils.h @@ -0,0 +1,39 @@ +/** GSAVUtils + + Utilities to handle AVPacket structs + + Copyright (C) 2025 Free Software Foundation, Inc. + + Author: Gregory Casamento + Date: May 2025 + + This file is part of the GNUstep GUI Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; see the file COPYING.LIB. + If not, see or write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _GNUstep_H_GSAVUtils +#define _GNUstep_H_GSAVUtils + +/* FFmpeg headers */ +#include +#include + +NSDictionary *NSDictionaryFromAVPacket(AVPacket *packet); +AVPacket AVPacketFromNSDictionary(NSDictionary *dict); + +#endif // GSAVUtils... diff --git a/Source/GSAVUtils.m b/Source/GSAVUtils.m new file mode 100644 index 0000000000..8179335008 --- /dev/null +++ b/Source/GSAVUtils.m @@ -0,0 +1,65 @@ +/** GSAVUtils + + Utilities to handle AVPacket structs + + Copyright (C) 2025 Free Software Foundation, Inc. + + Author: Gregory Casamento + Date: May 2025 + + This file is part of the GNUstep GUI Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; see the file COPYING.LIB. + If not, see or write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#import +#import +#import + +#import "GSAVUtils.h" + +NSDictionary *NSDictionaryFromAVPacket(AVPacket *packet) +{ + NSData *data = [NSData dataWithBytes:packet->data length:packet->size]; + NSNumber *pts = [NSNumber numberWithLongLong:packet->pts]; + NSNumber *duration = [NSNumber numberWithInt:packet->duration]; + NSNumber *flags = [NSNumber numberWithInt:packet->flags]; + + return [NSDictionary dictionaryWithObjectsAndKeys: + data, @"data", + pts, @"pts", + duration, @"duration", + flags, @"flags", + nil]; +} + +AVPacket AVPacketFromNSDictionary(NSDictionary *dict) +{ + NSData *data = [dict objectForKey:@"data"]; + NSNumber *pts = [dict objectForKey:@"pts"]; + NSNumber *duration = [dict objectForKey:@"duration"]; + NSNumber *flags = [dict objectForKey:@"flags"]; + + AVPacket *packet = av_packet_alloc(); + packet->data = (uint8_t *)[data bytes]; + packet->size = (int)[data length]; + packet->pts = [pts longLongValue]; + packet->duration = [duration intValue]; + packet->flags = [flags intValue]; + + return *packet; +} diff --git a/Source/GSAudioPlayer.h b/Source/GSAudioPlayer.h new file mode 100644 index 0000000000..d4b523cc0d --- /dev/null +++ b/Source/GSAudioPlayer.h @@ -0,0 +1,96 @@ +/** GSAudioPlayer + + This class is just a quick sound player for GSMovieView + + Copyright (C) 2003 Free Software Foundation, Inc. + + Author: Gregory John Casamento + Date: May 2025 + + This file is part of the GNUstep GUI Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; see the file COPYING.LIB. + If not, see or write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _GNUstep_H_GSAudioPlayer +#define _GNUstep_H_GSAudioPlayer + +#import "config.h" + +#import +#import "AppKit/NSMovieView.h" + +#include +#include + +/* FFmpeg headers */ +#include +#include +#include +#include +#include +#include +#include + +@class NSMutableArray; +@class NSThread; + +// Audio player for NSMovieView... +@interface GSAudioPlayer : NSObject +{ + AVCodecContext *_audioCodecCtx; + AVFrame *_audioFrame; + SwrContext *_swrCtx; + ao_device *_aoDev; + ao_sample_format _aoFmt; + int64_t _audioClock; + AVRational _timeBase; + float _volume; /* 0.0 to 1.0 */ + unsigned int _loopMode:3; + + NSMutableArray *_audioPackets; + NSThread *_audioThread; + + BOOL _running; + BOOL _started; + BOOL _muted; + BOOL _paused; +} + +- (void) prepareAudioWithFormatContext: (AVFormatContext *)formatCtx + streamIndex: (int)audioStreamIndex; +- (void) decodeAudioPacket: (AVPacket *)packet; +- (void) submitPacket: (AVPacket *)packet; +- (void) startAudio; +- (void) stopAudio; + +- (float) volume; +- (void) setVolume: (float)volume; + +- (NSQTMovieLoopMode) loopMode; +- (void) setLoopMode: (NSQTMovieLoopMode)mode; + +- (void) setMuted: (BOOL)muted; +- (BOOL) isMuted; +- (void) setPaused: (BOOL)f; +- (BOOL) isPaused; +- (void) setPlaying: (BOOL)f; +- (BOOL) isPlaying; + +@end + +#endif // end of _GNUstep_H_GSAudioPlayer diff --git a/Source/GSAudioPlayer.m b/Source/GSAudioPlayer.m new file mode 100644 index 0000000000..4b250ec911 --- /dev/null +++ b/Source/GSAudioPlayer.m @@ -0,0 +1,335 @@ +/** GSAudioPlayer + + Encapsulate a movie + + Copyright (C) 2025 Free Software Foundation, Inc. + + Author: Gregory Casamento + Date: May 2025 + + This file is part of the GNUstep GUI Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; see the file COPYING.LIB. + If not, see or write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#import "GSAudioPlayer.h" +#import "GSAVUtils.h" + +@implementation GSAudioPlayer +- (instancetype) init +{ + self = [super init]; + if (self != nil) + { + _audioCodecCtx = NULL; + _audioFrame = NULL; + _swrCtx = NULL; + _audioClock = 0; + _audioPackets = nil; + _audioThread = nil; + _running = NO; + _volume = 1.0; + _started = NO; + _paused = NO; + _loopMode = NSQTMovieNormalPlayback; + } + return self; +} + +- (void)dealloc +{ + [self stopAudio]; + + if (_audioFrame) + { + av_frame_free(&_audioFrame); + } + + if (_audioCodecCtx) + { + avcodec_free_context(&_audioCodecCtx); + } + + if (_swrCtx) + { + swr_free(&_swrCtx); + } + + if (_aoDev) + { + ao_close(_aoDev); + } + + RELEASE(_audioPackets); + + ao_shutdown(); + [super dealloc]; +} + +- (void) setPaused: (BOOL)f; +{ + _paused = f; +} + +- (BOOL) isPaused +{ + return _paused; +} + +- (void) setPlaying: (BOOL)f +{ + _running = f; +} + +- (BOOL) isPlaying +{ + return _running; +} + +- (NSQTMovieLoopMode) loopMode +{ + return _loopMode; +} + +- (void) setLoopMode: (NSQTMovieLoopMode)mode +{ + _loopMode = mode; +} + +- (void) prepareAudioWithFormatContext: (AVFormatContext *)formatCtx + streamIndex: (int)audioStreamIndex +{ + ao_initialize(); + int driver = ao_default_driver_id(); + int out_channels = 2; + + AVCodecParameters *audioPar = formatCtx->streams[audioStreamIndex]->codecpar; + const AVCodec *audioCodec = avcodec_find_decoder(audioPar->codec_id); + + if (!audioCodec) + { + NSLog(@"Audio codec not found."); + return; + } + + _audioCodecCtx = avcodec_alloc_context3(audioCodec); + avcodec_parameters_to_context(_audioCodecCtx, audioPar); + + if (avcodec_open2(_audioCodecCtx, audioCodec, NULL) < 0) + { + NSLog(@"Failed to open audio codec."); + return; + } + + _audioFrame = av_frame_alloc(); + swr_alloc_set_opts2(&_swrCtx, + &(AVChannelLayout){ .order = AV_CHANNEL_ORDER_NATIVE, + .nb_channels = out_channels, + .u.mask = AV_CH_LAYOUT_STEREO }, + AV_SAMPLE_FMT_S16, + _audioCodecCtx->sample_rate, + &_audioCodecCtx->ch_layout, + _audioCodecCtx->sample_fmt, + _audioCodecCtx->sample_rate, + 0, NULL); + int r = swr_init(_swrCtx); + if (r == 0) + { + NSLog(@"[GSMovieView] WARNING: swr_init returned 0"); + } + + memset(&_aoFmt, 0, sizeof(ao_sample_format)); + _aoFmt.bits = 16; + _aoFmt.channels = out_channels; + _aoFmt.rate = _audioCodecCtx->sample_rate; + _aoFmt.byte_format = AO_FMT_NATIVE; + + _aoDev = ao_open_live(driver, &_aoFmt, NULL); + _timeBase = formatCtx->streams[audioStreamIndex]->time_base; + _audioClock = av_gettime(); + _audioPackets = [[NSMutableArray alloc] init]; + _running = YES; +} + +- (void)audioThreadEntry +{ + while (_running) + { + // Stop reading packets while paused... + if (_paused == YES) + { + usleep(10000); // 10ms pause + continue; // start the loop again... + } + + // create pool... + CREATE_AUTORELEASE_POOL(pool); + { + NSDictionary *dict = nil; + + @synchronized (_audioPackets) + { + if (!_started && [_audioPackets count] < 5) + { + usleep(5000); + continue; + } + + if ([_audioPackets count] > 0) + { + dict = [[_audioPackets objectAtIndex:0] retain]; + [_audioPackets removeObjectAtIndex:0]; + } + } + + if (!_started && dict) + { + _audioClock = av_gettime(); + _started = YES; + } + + if (dict) + { + AVPacket packet = AVPacketFromNSDictionary(dict); + int64_t packetTime = av_rescale_q(packet.pts, _timeBase, (AVRational){1, 1000000}); + int64_t now = av_gettime() - _audioClock; + int64_t delay = packetTime - now; + if (delay > 0) + usleep((useconds_t)delay); + + [self decodeAudioPacket:&packet]; + [dict release]; + } + else + { + usleep(1000); + } + } + RELEASE(pool); + } +} + +- (void)decodeAudioPacket: (AVPacket *)packet +{ + if (!_audioCodecCtx || !_swrCtx || !_aoDev) + { + return; + } + + if (avcodec_send_packet(_audioCodecCtx, packet) < 0) + { + return; + } + + if (packet->flags & AV_PKT_FLAG_CORRUPT) + { + NSLog(@"Skipping corrupt audio packet"); + return; + } + + while (avcodec_receive_frame(_audioCodecCtx, _audioFrame) == 0) + { + int outSamples = _audioFrame->nb_samples; + int outBytes = av_samples_get_buffer_size(NULL, 2, outSamples, AV_SAMPLE_FMT_S16, 1); + uint8_t *outBuf = (uint8_t *) malloc(outBytes); + uint8_t *outPtrs[] = { outBuf }; + + swr_convert(_swrCtx, outPtrs, outSamples, + (const uint8_t **) _audioFrame->data, + outSamples); + + // Apply volume + int16_t *samples = (int16_t *)outBuf; + int i = 0; + for (i = 0; i < outBytes / 2; ++i) + { + if ([self isMuted]) + { + samples[i] = 0.0; + } + else + { + samples[i] = samples[i] * _volume; + } + } + + ao_play(_aoDev, (char *) outBuf, outBytes); + free(outBuf); + } +} + +- (void) submitPacket: (AVPacket *)packet +{ + NSDictionary *dict = NSDictionaryFromAVPacket(packet); + @synchronized (_audioPackets) + { + [_audioPackets addObject: dict]; + } +} + +- (void) startAudio +{ + _running = YES; + NSLog(@"[GSMovieView] Starting audio thread | Timestamp: %ld", av_gettime()); + _audioThread = [[NSThread alloc] initWithTarget:self selector:@selector(audioThreadEntry) object:nil]; + [_audioThread start]; +} + +- (void) stopAudio +{ + _running = NO; + [_audioThread cancel]; + + while ([_audioThread isFinished] == NO) + { + usleep(1000); + } + + DESTROY(_audioThread); +} + +- (void) setVolume: (float)volume +{ + if (volume < 0.0) + { + volume = 0.0; + } + + if (volume > 1.0) + { + volume = 1.0; + } + + _volume = volume; +} + +- (float) volume +{ + return _volume; +} + +- (void) setMuted: (BOOL)muted +{ + _muted = muted; +} + +- (BOOL) isMuted +{ + return _muted; +} + +@end diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index e5b87b3c94..07c8e9b8c4 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -46,43 +46,10 @@ #import "GSMovieView.h" #import "GSAudioPlayer.h" - -#include +#import "GSAVUtils.h" static NSNotificationCenter *nc = nil; -static NSDictionary *NSDictionaryFromAVPacket(AVPacket *packet) -{ - NSData *data = [NSData dataWithBytes:packet->data length:packet->size]; - NSNumber *pts = [NSNumber numberWithLongLong:packet->pts]; - NSNumber *duration = [NSNumber numberWithInt:packet->duration]; - NSNumber *flags = [NSNumber numberWithInt:packet->flags]; - - return [NSDictionary dictionaryWithObjectsAndKeys: - data, @"data", - pts, @"pts", - duration, @"duration", - flags, @"flags", - nil]; -} - -static AVPacket AVPacketFromNSDictionary(NSDictionary *dict) -{ - NSData *data = [dict objectForKey:@"data"]; - NSNumber *pts = [dict objectForKey:@"pts"]; - NSNumber *duration = [dict objectForKey:@"duration"]; - NSNumber *flags = [dict objectForKey:@"flags"]; - - AVPacket *packet = av_packet_alloc(); - packet->data = (uint8_t *)[data bytes]; - packet->size = (int)[data length]; - packet->pts = [pts longLongValue]; - packet->duration = [duration intValue]; - packet->flags = [flags intValue]; - - return *packet; -} - // Ignore the warning this will produce as it is intentional. #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation" @@ -138,311 +105,6 @@ + (NSArray*) movieUnfilteredPasteboardTypes #pragma clang diagnostic pop -@implementation GSAudioPlayer -- (instancetype) init -{ - self = [super init]; - if (self != nil) - { - _audioCodecCtx = NULL; - _audioFrame = NULL; - _swrCtx = NULL; - _audioClock = 0; - _audioPackets = nil; - _audioThread = nil; - _running = NO; - _volume = 1.0; - _started = NO; - _paused = NO; - _loopMode = NSQTMovieNormalPlayback; - } - return self; -} - -- (void)dealloc -{ - [self stopAudio]; - - if (_audioFrame) - { - av_frame_free(&_audioFrame); - } - - if (_audioCodecCtx) - { - avcodec_free_context(&_audioCodecCtx); - } - - if (_swrCtx) - { - swr_free(&_swrCtx); - } - - if (_aoDev) - { - ao_close(_aoDev); - } - - RELEASE(_audioPackets); - - ao_shutdown(); - [super dealloc]; -} - -- (void) setPaused: (BOOL)f; -{ - _paused = f; -} - -- (BOOL) isPaused -{ - return _paused; -} - -- (void) setPlaying: (BOOL)f -{ - _running = f; -} - -- (BOOL) isPlaying -{ - return _running; -} - -- (NSQTMovieLoopMode) loopMode -{ - return _loopMode; -} - -- (void) setLoopMode: (NSQTMovieLoopMode)mode -{ - _loopMode = mode; -} - -- (void) prepareAudioWithFormatContext: (AVFormatContext *)formatCtx - streamIndex: (int)audioStreamIndex -{ - ao_initialize(); - int driver = ao_default_driver_id(); - int out_channels = 2; - - AVCodecParameters *audioPar = formatCtx->streams[audioStreamIndex]->codecpar; - const AVCodec *audioCodec = avcodec_find_decoder(audioPar->codec_id); - - if (!audioCodec) - { - NSLog(@"Audio codec not found."); - return; - } - - _audioCodecCtx = avcodec_alloc_context3(audioCodec); - avcodec_parameters_to_context(_audioCodecCtx, audioPar); - - if (avcodec_open2(_audioCodecCtx, audioCodec, NULL) < 0) - { - NSLog(@"Failed to open audio codec."); - return; - } - - _audioFrame = av_frame_alloc(); - swr_alloc_set_opts2(&_swrCtx, - &(AVChannelLayout){ .order = AV_CHANNEL_ORDER_NATIVE, - .nb_channels = out_channels, - .u.mask = AV_CH_LAYOUT_STEREO }, - AV_SAMPLE_FMT_S16, - _audioCodecCtx->sample_rate, - &_audioCodecCtx->ch_layout, - _audioCodecCtx->sample_fmt, - _audioCodecCtx->sample_rate, - 0, NULL); - int r = swr_init(_swrCtx); - if (r == 0) - { - NSLog(@"[GSMovieView] WARNING: swr_init returned 0"); - } - - memset(&_aoFmt, 0, sizeof(ao_sample_format)); - _aoFmt.bits = 16; - _aoFmt.channels = out_channels; - _aoFmt.rate = _audioCodecCtx->sample_rate; - _aoFmt.byte_format = AO_FMT_NATIVE; - - _aoDev = ao_open_live(driver, &_aoFmt, NULL); - _timeBase = formatCtx->streams[audioStreamIndex]->time_base; - _audioClock = av_gettime(); - _audioPackets = [[NSMutableArray alloc] init]; - _running = YES; -} - -- (void)audioThreadEntry -{ - while (_running) - { - // Stop reading packets while paused... - if (_paused == YES) - { - usleep(10000); // 10ms pause - continue; // start the loop again... - } - - // create pool... - CREATE_AUTORELEASE_POOL(pool); - { - NSDictionary *dict = nil; - - @synchronized (_audioPackets) - { - if (!_started && [_audioPackets count] < 5) - { - usleep(5000); - continue; - } - - if ([_audioPackets count] > 0) - { - dict = [[_audioPackets objectAtIndex:0] retain]; - [_audioPackets removeObjectAtIndex:0]; - } - } - - if (!_started && dict) - { - _audioClock = av_gettime(); - _started = YES; - } - - if (dict) - { - AVPacket packet = AVPacketFromNSDictionary(dict); - int64_t packetTime = av_rescale_q(packet.pts, _timeBase, (AVRational){1, 1000000}); - int64_t now = av_gettime() - _audioClock; - int64_t delay = packetTime - now; - if (delay > 0) - usleep((useconds_t)delay); - - [self decodeAudioPacket:&packet]; - [dict release]; - } - else - { - usleep(1000); - } - } - RELEASE(pool); - } -} - -- (void)decodeAudioPacket: (AVPacket *)packet -{ - if (!_audioCodecCtx || !_swrCtx || !_aoDev) - { - return; - } - - if (avcodec_send_packet(_audioCodecCtx, packet) < 0) - { - return; - } - - if (packet->flags & AV_PKT_FLAG_CORRUPT) - { - NSLog(@"Skipping corrupt audio packet"); - return; - } - - while (avcodec_receive_frame(_audioCodecCtx, _audioFrame) == 0) - { - int outSamples = _audioFrame->nb_samples; - int outBytes = av_samples_get_buffer_size(NULL, 2, outSamples, AV_SAMPLE_FMT_S16, 1); - uint8_t *outBuf = (uint8_t *) malloc(outBytes); - uint8_t *outPtrs[] = { outBuf }; - - swr_convert(_swrCtx, outPtrs, outSamples, - (const uint8_t **) _audioFrame->data, - outSamples); - - // Apply volume - int16_t *samples = (int16_t *)outBuf; - int i = 0; - for (i = 0; i < outBytes / 2; ++i) - { - if ([self isMuted]) - { - samples[i] = 0.0; - } - else - { - samples[i] = samples[i] * _volume; - } - } - - ao_play(_aoDev, (char *) outBuf, outBytes); - free(outBuf); - } -} - -- (void)submitPacket: (AVPacket *)packet -{ - NSDictionary *dict = NSDictionaryFromAVPacket(packet); - @synchronized (_audioPackets) - { - [_audioPackets addObject: dict]; - } -} - -- (void)startAudio -{ - _running = YES; - NSLog(@"[GSMovieView] Starting audio thread | Timestamp: %ld", av_gettime()); - _audioThread = [[NSThread alloc] initWithTarget:self selector:@selector(audioThreadEntry) object:nil]; - [_audioThread start]; -} - -- (void)stopAudio -{ - _running = NO; - [_audioThread cancel]; - - while ([_audioThread isFinished] == NO) - { - usleep(1000); - } - - DESTROY(_audioThread); -} - -- (void) setVolume: (float)volume -{ - if (volume < 0.0) - { - volume = 0.0; - } - - if (volume > 1.0) - { - volume = 1.0; - } - - _volume = volume; -} - -- (float) volume -{ - return _volume; -} - -- (void) setMuted: (BOOL)muted -{ - _muted = muted; -} - -- (BOOL) isMuted -{ - return _muted; -} - -@end - // NSMovieView subclass that does all of the actual work of decoding... @implementation GSMovieView From aa1320495c8c73c68ed965395f548916b202e30e Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Tue, 10 Jun 2025 03:56:47 -0400 Subject: [PATCH 60/86] Pause sound and video when movie is paused --- Source/GSMovieView.m | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 07c8e9b8c4..6352158ba2 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -42,7 +42,6 @@ #import "AppKit/NSImageRep.h" #import "AppKit/NSMovie.h" #import "AppKit/NSPasteboard.h" -#import "AppKit/NSSound.h" #import "GSMovieView.h" #import "GSAudioPlayer.h" @@ -188,6 +187,7 @@ - (void)dealloc - (void) setPaused: (BOOL)f { _paused = f; + [_audioPlayer setPaused: f]; } - (BOOL) isPaused @@ -239,12 +239,12 @@ - (BOOL) isPlaying - (IBAction) start: (id)sender { - [self setPlaying: YES]; + [self setPaused: NO]; } - (IBAction) stop: (id)sender { - [self setPlaying: NO]; + [self setPaused: YES]; } - (void) setMuted: (BOOL)muted @@ -589,7 +589,6 @@ - (void) stopVideo - (void) setPlaying: (BOOL)f { _running = f; - [_audioPlayer setPlaying: _running]; } - (void)submitVideoPacket: (AVPacket *)packet From 61967d6bc50dc94283f264d2503b73065ee9514f Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Wed, 11 Jun 2025 23:16:17 -0400 Subject: [PATCH 61/86] Optimize some of the code, change logging --- Source/GSAudioPlayer.m | 21 ++++++++++++--------- Source/GSMovieView.m | 27 +++++++++++++++++++-------- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/Source/GSAudioPlayer.m b/Source/GSAudioPlayer.m index 4b250ec911..8851388aba 100644 --- a/Source/GSAudioPlayer.m +++ b/Source/GSAudioPlayer.m @@ -149,7 +149,7 @@ - (void) prepareAudioWithFormatContext: (AVFormatContext *)formatCtx int r = swr_init(_swrCtx); if (r == 0) { - NSLog(@"[GSMovieView] WARNING: swr_init returned 0"); + NSLog(@"[GSAudioPlayer] WARNING: swr_init returned 0"); } memset(&_aoFmt, 0, sizeof(ao_sample_format)); @@ -183,12 +183,6 @@ - (void)audioThreadEntry @synchronized (_audioPackets) { - if (!_started && [_audioPackets count] < 5) - { - usleep(5000); - continue; - } - if ([_audioPackets count] > 0) { dict = [[_audioPackets objectAtIndex:0] retain]; @@ -208,8 +202,11 @@ - (void)audioThreadEntry int64_t packetTime = av_rescale_q(packet.pts, _timeBase, (AVRational){1, 1000000}); int64_t now = av_gettime() - _audioClock; int64_t delay = packetTime - now; + if (delay > 0) - usleep((useconds_t)delay); + { + usleep((useconds_t)delay); // + 50000); + } [self decodeAudioPacket:&packet]; [dict release]; @@ -275,6 +272,12 @@ - (void)decodeAudioPacket: (AVPacket *)packet - (void) submitPacket: (AVPacket *)packet { NSDictionary *dict = NSDictionaryFromAVPacket(packet); + + if (_paused) + { + NSLog(@"Submitted audio packet..."); + } + @synchronized (_audioPackets) { [_audioPackets addObject: dict]; @@ -284,7 +287,7 @@ - (void) submitPacket: (AVPacket *)packet - (void) startAudio { _running = YES; - NSLog(@"[GSMovieView] Starting audio thread | Timestamp: %ld", av_gettime()); + NSLog(@"[GSAudioPlayer] Starting audio thread | Timestamp: %ld", av_gettime()); _audioThread = [[NSThread alloc] initWithTarget:self selector:@selector(audioThreadEntry) object:nil]; [_audioThread start]; } diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 6352158ba2..56348948d1 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -335,8 +335,19 @@ - (IBAction) stepForward: (id)sender int64_t seconds = 2; int64_t skip = av_rescale_q(seconds, (AVRational){1,1}, _stream->time_base); int64_t newPts = _lastPts + skip; - av_seek_frame(_formatCtx, _videoStreamIndex, newPts, AVSEEK_FLAG_BACKWARD); - avcodec_flush_buffers(_videoCodecCtx); + + if (_paused == NO) + { + _paused = YES; + av_seek_frame(_formatCtx, _videoStreamIndex, newPts, AVSEEK_FLAG_BACKWARD); + avcodec_flush_buffers(_videoCodecCtx); + _paused = NO; + } + else + { + av_seek_frame(_formatCtx, _videoStreamIndex, newPts, AVSEEK_FLAG_BACKWARD); + avcodec_flush_buffers(_videoCodecCtx); + } } - (IBAction) stepBack: (id)sender @@ -594,6 +605,12 @@ - (void) setPlaying: (BOOL)f - (void)submitVideoPacket: (AVPacket *)packet { NSDictionary *dict = NSDictionaryFromAVPacket(packet); + + if (_paused) + { + NSLog(@"Submitted packet..."); + } + @synchronized (_videoPackets) { [_videoPackets addObject: dict]; @@ -620,12 +637,6 @@ - (void)videoThreadEntry // the array. @synchronized (_videoPackets) { - if (!_started && [_videoPackets count] < 3) - { - usleep(5000); - RELEASE(pool); - continue; - } if ([_videoPackets count] > 0) { dict = RETAIN([_videoPackets objectAtIndex: 0]); From e0714517a49e369175d40233b1ac5541a0c7a128 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Sat, 14 Jun 2025 18:36:56 -0400 Subject: [PATCH 62/86] Cleanup, refactor --- Source/GSAudioPlayer.h | 7 ++++--- Source/GSAudioPlayer.m | 8 ++++---- Source/GSMovieView.h | 9 +++++---- Source/GSMovieView.m | 27 ++++++++++++++++----------- Source/NSMovieView.m | 4 +++- 5 files changed, 32 insertions(+), 23 deletions(-) diff --git a/Source/GSAudioPlayer.h b/Source/GSAudioPlayer.h index d4b523cc0d..c7684230d9 100644 --- a/Source/GSAudioPlayer.h +++ b/Source/GSAudioPlayer.h @@ -71,9 +71,10 @@ BOOL _paused; } -- (void) prepareAudioWithFormatContext: (AVFormatContext *)formatCtx - streamIndex: (int)audioStreamIndex; -- (void) decodeAudioPacket: (AVPacket *)packet; +- (void) prepareWithFormatContext: (AVFormatContext *)formatCtx + streamIndex: (int)audioStreamIndex; + +- (void) decodePacket: (AVPacket *)packet; - (void) submitPacket: (AVPacket *)packet; - (void) startAudio; - (void) stopAudio; diff --git a/Source/GSAudioPlayer.m b/Source/GSAudioPlayer.m index 8851388aba..d016020cd5 100644 --- a/Source/GSAudioPlayer.m +++ b/Source/GSAudioPlayer.m @@ -110,8 +110,8 @@ - (void) setLoopMode: (NSQTMovieLoopMode)mode _loopMode = mode; } -- (void) prepareAudioWithFormatContext: (AVFormatContext *)formatCtx - streamIndex: (int)audioStreamIndex +- (void) prepareWithFormatContext: (AVFormatContext *)formatCtx + streamIndex: (int)audioStreamIndex { ao_initialize(); int driver = ao_default_driver_id(); @@ -208,7 +208,7 @@ - (void)audioThreadEntry usleep((useconds_t)delay); // + 50000); } - [self decodeAudioPacket:&packet]; + [self decodePacket:&packet]; [dict release]; } else @@ -220,7 +220,7 @@ - (void)audioThreadEntry } } -- (void)decodeAudioPacket: (AVPacket *)packet +- (void)decodePacket: (AVPacket *)packet { if (!_audioCodecCtx || !_swrCtx || !_aoDev) { diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index 328f98ccf8..2535250f89 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -73,15 +73,16 @@ APPKIT_EXPORT_CLASS int _audioStreamIndex; int64_t _lastPts; int64_t _savedPts; + CGFloat _fps; } // Initialization... -- (void) prepareVideoWithFormatContext: (AVFormatContext *)formatCtx - streamIndex: (int)videoStreamIndex; +- (void) prepareWithFormatContext: (AVFormatContext *)formatCtx + streamIndex: (int)videoStreamIndex; // Submit packets... -- (void) submitVideoPacket: (AVPacket *)packet; -- (void) decodeVideoPacket: (AVPacket *)packet; +- (void) submitPacket: (AVPacket *)packet; +- (void) decodePacket: (AVPacket *)packet; // Start and stop... - (void) startVideo; diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 56348948d1..a1cd77721b 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -123,21 +123,23 @@ - (instancetype) initWithFrame: (NSRect)frame self = [super initWithFrame: frame]; if (self != nil) { + // Objects... _currentFrame = nil; _videoThread = nil; _feedThread = nil; _audioPlayer = [[GSAudioPlayer alloc] init]; _videoPackets = [[NSMutableArray alloc] init]; - // AV + // AV... _videoClock = 0; _videoCodecCtx = NULL; _formatCtx = NULL; _swsCtx = NULL; _stream = NULL; _lastPts = 0; + _fps = 0.0; - // Flags + // Flags... _running = NO; _started = NO; _paused = NO; @@ -427,8 +429,8 @@ - (BOOL) setup } else { - [self prepareVideoWithFormatContext: _formatCtx - streamIndex: _videoStreamIndex]; + [self prepareWithFormatContext: _formatCtx + streamIndex: _videoStreamIndex]; } // Audio stream... @@ -438,8 +440,8 @@ - (BOOL) setup } else { - [_audioPlayer prepareAudioWithFormatContext: _formatCtx - streamIndex: _audioStreamIndex]; + [_audioPlayer prepareWithFormatContext: _formatCtx + streamIndex: _audioStreamIndex]; } // Video and Audio stream not present... @@ -478,7 +480,7 @@ - (void) loop if (packet.stream_index == _videoStreamIndex) { - [self submitVideoPacket: &packet]; + [self submitPacket: &packet]; } if (packet.stream_index == _audioStreamIndex) @@ -522,11 +524,14 @@ - (void) feedVideo } } -- (void)prepareVideoWithFormatContext: (AVFormatContext *)formatCtx streamIndex: (int)videoStreamIndex +- (void)prepareWithFormatContext: (AVFormatContext *)formatCtx streamIndex: (int)videoStreamIndex { + AVStream *videoStream = formatCtx->streams[videoStreamIndex]; AVCodecParameters *videoPar = formatCtx->streams[videoStreamIndex]->codecpar; const AVCodec *videoCodec = avcodec_find_decoder(videoPar->codec_id); + AVRational fr = videoStream->avg_frame_rate; + _fps = av_q2d(fr); if (!videoCodec) { NSLog(@"[Error] Unsupported video codec. | Timestamp: %ld", av_gettime()); @@ -602,7 +607,7 @@ - (void) setPlaying: (BOOL)f _running = f; } -- (void)submitVideoPacket: (AVPacket *)packet +- (void)submitPacket: (AVPacket *)packet { NSDictionary *dict = NSDictionaryFromAVPacket(packet); @@ -684,7 +689,7 @@ - (void)videoThreadEntry } // Decode the packet, display it and play the sound... - [self decodeVideoPacket: &packet]; + [self decodePacket: &packet]; RELEASE(dict); } else @@ -738,7 +743,7 @@ - (void) renderFrame: (AVFrame *)videoFrame free(rgbData[0]); } -- (void) decodeVideoPacket: (AVPacket *)packet +- (void) decodePacket: (AVPacket *)packet { if (!_videoCodecCtx || !_swsCtx) { diff --git a/Source/NSMovieView.m b/Source/NSMovieView.m index 22c7ccab71..4e6d9ff32c 100644 --- a/Source/NSMovieView.m +++ b/Source/NSMovieView.m @@ -66,8 +66,10 @@ - (instancetype) initWithFrame: (NSRect)frame if (self != nil) { _movie = nil; - _rate = 0.0; + _rate = 1.0; _volume = 1.0; + + // Flags... _flags.muted = NO; _flags.loopMode = NSQTMovieNormalPlayback; _flags.plays_selection_only = NO; From ad634be239851b36c7356c8a1f49d47946f6b0c4 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Sat, 14 Jun 2025 19:19:05 -0400 Subject: [PATCH 63/86] Streamline getting the movieRect so that it doesn't need to get the stream separately --- Source/GSMovieView.h | 1 + Source/GSMovieView.m | 70 ++++++++++++++++++-------------------------- 2 files changed, 30 insertions(+), 41 deletions(-) diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index 2535250f89..ccdc4be144 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -57,6 +57,7 @@ APPKIT_EXPORT_CLASS NSImage *_currentFrame; NSString *_statusString; GSAudioPlayer *_audioPlayer; + NSLock *_lock; AVCodecContext *_videoCodecCtx; AVFrame *_videoFrame; diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index a1cd77721b..27f43ff04d 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -129,6 +129,7 @@ - (instancetype) initWithFrame: (NSRect)frame _feedThread = nil; _audioPlayer = [[GSAudioPlayer alloc] init]; _videoPackets = [[NSMutableArray alloc] init]; + _lock = [[NSLock alloc] init]; // AV... _videoClock = 0; @@ -156,10 +157,10 @@ - (void)dealloc { [self stop: nil]; + // Cancel thread, dealloc av structs... if (_feedThread) { [_feedThread cancel]; - DESTROY(_feedThread); } if (_videoFrame) @@ -177,9 +178,14 @@ - (void)dealloc sws_freeContext(_swsCtx); } - TEST_RELEASE(_currentFrame); + // Destroy objects + DESTROY(_feedThread); + DESTROY(_lock); DESTROY(_videoPackets); DESTROY(_audioPlayer); + DESTROY(_currentFrame); + + // Unsubscribe to NSNotification [nc removeObserver: self]; [super dealloc]; @@ -271,46 +277,28 @@ - (void) setMovie: (NSMovie *)movie @synchronized(_movie) { [super setMovie: movie]; + [self setup]; [self _startFeed]; } } - (NSRect) movieRect { - AVFormatContext* fmt_ctx = NULL; - NSURL *url = [[self movie] URL]; - const char *name = [[url path] UTF8String]; - - // I realize this is inefficient, but there is a race condition - // which occurs when setting this from the existing stream. - // The issue with using the ivars is that they are initialized on - // a thread, so they may not be set when this is called. - - // Open video file - avformat_open_input(&fmt_ctx, name, NULL, NULL); - avformat_find_stream_info(fmt_ctx, NULL); - - // Find the first video stream - int video_stream_index = -1; - unsigned int i = 0; - for (i = 0; i < fmt_ctx->nb_streams; i++) + NSRect result = NSZeroRect; + + if (_stream != NULL) { - if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) - { - video_stream_index = i; - break; - } + // Retrieve codec parameters + AVCodecParameters* codecpar = _stream->codecpar; + + // These are your video dimensions: + CGFloat width = (CGFloat)(codecpar->width); + CGFloat height = (CGFloat)(codecpar->height); + + result = NSMakeRect(0.0, 0.0, width, height); } - // Retrieve codec parameters - AVCodecParameters* codecpar = - fmt_ctx->streams[video_stream_index]->codecpar; - - // These are your video dimensions: - CGFloat width = (CGFloat)(codecpar->width); - CGFloat height = (CGFloat)(codecpar->height); - - return NSMakeRect(0.0, 0.0, width, height); + return result; } - (IBAction)gotoPosterFrame: (id)sender @@ -377,7 +365,7 @@ - (void) drawRect: (NSRect)dirtyRect - (BOOL) setup { NSMovie *movie = [self movie]; - + if (movie != nil) { NSURL *url = [movie URL]; @@ -512,25 +500,23 @@ - (void) close - (void) feedVideo { - BOOL success = [self setup]; - if (success) + if (_stream != NULL) { [self loop]; [self close]; } - else - { - NSLog(@"[GSMovieView] setup failed."); - } } - (void)prepareWithFormatContext: (AVFormatContext *)formatCtx streamIndex: (int)videoStreamIndex { + // [_lock lock]; + AVStream *videoStream = formatCtx->streams[videoStreamIndex]; - AVCodecParameters *videoPar = formatCtx->streams[videoStreamIndex]->codecpar; + AVCodecParameters *videoPar = videoStream->codecpar; const AVCodec *videoCodec = avcodec_find_decoder(videoPar->codec_id); AVRational fr = videoStream->avg_frame_rate; + _stream = videoStream; _fps = av_q2d(fr); if (!videoCodec) { @@ -564,6 +550,8 @@ - (void)prepareWithFormatContext: (AVFormatContext *)formatCtx streamIndex: (int _videoClock = av_gettime(); _running = NO; _started = NO; + + // [_lock unlock]; } - (void) startVideo From 1bd131d9ea69e2c365039ffda68e256e76ec2979 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Sat, 14 Jun 2025 19:57:17 -0400 Subject: [PATCH 64/86] Remove lock --- Source/GSMovieView.h | 1 - Source/GSMovieView.m | 14 ++++---------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index ccdc4be144..2535250f89 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -57,7 +57,6 @@ APPKIT_EXPORT_CLASS NSImage *_currentFrame; NSString *_statusString; GSAudioPlayer *_audioPlayer; - NSLock *_lock; AVCodecContext *_videoCodecCtx; AVFrame *_videoFrame; diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 27f43ff04d..e8c6ae158c 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -129,7 +129,6 @@ - (instancetype) initWithFrame: (NSRect)frame _feedThread = nil; _audioPlayer = [[GSAudioPlayer alloc] init]; _videoPackets = [[NSMutableArray alloc] init]; - _lock = [[NSLock alloc] init]; // AV... _videoClock = 0; @@ -141,10 +140,11 @@ - (instancetype) initWithFrame: (NSRect)frame _fps = 0.0; // Flags... - _running = NO; - _started = NO; - _paused = NO; + _running = NO; // is the thread running? + _started = NO; // have we started processing packets... + _paused = NO; // is the stream paused? + // Get notifications and shut down the thread if app is closing. [nc addObserver: self selector: @selector(handleNotification:) name: NSApplicationWillTerminateNotification @@ -180,7 +180,6 @@ - (void)dealloc // Destroy objects DESTROY(_feedThread); - DESTROY(_lock); DESTROY(_videoPackets); DESTROY(_audioPlayer); DESTROY(_currentFrame); @@ -509,8 +508,6 @@ - (void) feedVideo - (void)prepareWithFormatContext: (AVFormatContext *)formatCtx streamIndex: (int)videoStreamIndex { - // [_lock lock]; - AVStream *videoStream = formatCtx->streams[videoStreamIndex]; AVCodecParameters *videoPar = videoStream->codecpar; const AVCodec *videoCodec = avcodec_find_decoder(videoPar->codec_id); @@ -549,9 +546,6 @@ - (void)prepareWithFormatContext: (AVFormatContext *)formatCtx streamIndex: (int _videoPackets = [[NSMutableArray alloc] init]; _videoClock = av_gettime(); _running = NO; - _started = NO; - - // [_lock unlock]; } - (void) startVideo From 0fd1bf3b5cb80b262b0a6be9a60f8706edf59279 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Sun, 15 Jun 2025 00:10:05 -0400 Subject: [PATCH 65/86] Implement frameRateForStream: --- Source/GSMovieView.h | 1 + Source/GSMovieView.m | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index 2535250f89..07ec9cff8b 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -89,6 +89,7 @@ APPKIT_EXPORT_CLASS - (void) stopVideo; - (void) setPaused: (BOOL)f; - (BOOL) isPaused; +- (CGFloat) frameRateForStream: (AVStream *)stream; // Main loop to process packets... - (void) renderFrame: (AVFrame *)videoFrame; diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index e8c6ae158c..e2cf1cf977 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -191,6 +191,14 @@ - (void)dealloc } // New methods... +- (CGFloat) frameRateForStream: (AVStream *)stream +{ + if (stream->avg_frame_rate.num > 0 && stream->avg_frame_rate.den > 0) + return av_q2d(stream->avg_frame_rate); + else + return 1.0 / av_q2d(stream->time_base); +} + - (void) setPaused: (BOOL)f { _paused = f; From b8450b7192fb4a4d83d0568e8b42696417718a08 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Sun, 15 Jun 2025 04:22:24 -0400 Subject: [PATCH 66/86] Use new method to get frameRateForStream: to get the framerate --- Source/GSMovieView.m | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index e2cf1cf977..f41eac4a00 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -516,13 +516,14 @@ - (void) feedVideo - (void)prepareWithFormatContext: (AVFormatContext *)formatCtx streamIndex: (int)videoStreamIndex { - AVStream *videoStream = formatCtx->streams[videoStreamIndex]; - AVCodecParameters *videoPar = videoStream->codecpar; - const AVCodec *videoCodec = avcodec_find_decoder(videoPar->codec_id); - AVRational fr = videoStream->avg_frame_rate; + AVCodecParameters *videoPar = NULL; + const AVCodec *videoCodec = NULL; + + _stream = formatCtx->streams[videoStreamIndex]; + _fps = [self frameRateForStream: _stream]; + videoPar = _stream->codecpar; + videoCodec = avcodec_find_decoder(videoPar->codec_id); - _stream = videoStream; - _fps = av_q2d(fr); if (!videoCodec) { NSLog(@"[Error] Unsupported video codec. | Timestamp: %ld", av_gettime()); From fd42688a809b38d761580798c9bb14eb8a5d87f4 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 23 Jun 2025 07:22:01 -0400 Subject: [PATCH 67/86] Set rate to 1.0 --- Source/GSMovieView.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index f41eac4a00..c66c9d3a45 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -226,7 +226,7 @@ - (void) _startFeed { if (_running == NO) { - [self setRate: 1.0 / 30.0]; + [self setRate: 1.0]; [self setVolume: 1.0]; _savedPts = 0; From 3ed198562ea5acbfcaaf29fbe894850b44ab5eb0 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 23 Jun 2025 08:19:53 -0400 Subject: [PATCH 68/86] Initial add of timer --- Source/GSMovieView.h | 1 + Source/GSMovieView.m | 79 ++++++++++++++++++++------------------------ 2 files changed, 37 insertions(+), 43 deletions(-) diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index 07ec9cff8b..7b7bd58a22 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -54,6 +54,7 @@ APPKIT_EXPORT_CLASS NSMutableArray *_videoPackets; NSThread *_videoThread; NSThread *_feedThread; + NSTimer *_feedTimer; NSImage *_currentFrame; NSString *_statusString; GSAudioPlayer *_audioPlayer; diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index c66c9d3a45..74170419f2 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -129,7 +129,8 @@ - (instancetype) initWithFrame: (NSRect)frame _feedThread = nil; _audioPlayer = [[GSAudioPlayer alloc] init]; _videoPackets = [[NSMutableArray alloc] init]; - + _feedTimer = nil; + // AV... _videoClock = 0; _videoCodecCtx = NULL; @@ -226,13 +227,22 @@ - (void) _startFeed { if (_running == NO) { + NSTimeInterval fr = (double)(1/[self frameRateForStream: _stream]); + + NSLog(@"[GSMovieView] framerate = %f", fr); [self setRate: 1.0]; [self setVolume: 1.0]; - + _savedPts = 0; - _feedThread = [[NSThread alloc] initWithTarget:self selector:@selector(feedVideo) object:nil]; - [_feedThread start]; - [_audioPlayer startAudio]; + _feedTimer = [NSTimer scheduledTimerWithTimeInterval: fr + target: self + selector: @selector(loop) + userInfo: nil + repeats: YES]; + + // _feedThread = [[NSThread alloc] initWithTarget:self selector:@selector(feedVideo) object:nil]; + // [_feedThread start]; + // [_audioPlayer startAudio]; } } @@ -241,8 +251,9 @@ - (void) _stopFeed if (_running == YES) { _savedPts = _lastPts; - [_feedThread cancel]; - [_audioPlayer stopAudio]; + // [_feedThread cancel]; + // [_audioPlayer stopAudio]; + [_feedTimer invalidate]; } } @@ -457,43 +468,23 @@ - (void) loop if (_formatCtx != NULL) { AVPacket packet; - int64_t i = 0; - + while (av_read_frame(_formatCtx, &packet) >= 0) { - if (packet.pts <= _savedPts) - { - continue; - } - - // After 1000 frames, start the thread... - if (i == 1000) - { - [self startVideo]; - [_audioPlayer startAudio]; - } - if (packet.stream_index == _videoStreamIndex) { - [self submitPacket: &packet]; + [self decodePacket: &packet]; + break; } if (packet.stream_index == _audioStreamIndex) { - [_audioPlayer submitPacket: &packet]; + [_audioPlayer decodePacket: &packet]; + break; } - - av_packet_unref(&packet); - i++; - } - - // if we had a very short video... play it. - if (i < 1000) - { - NSLog(@"[GSMovieView] Starting short video... | Timestamp: %ld", av_gettime()); - [self startVideo]; - [_audioPlayer startAudio]; } + + av_packet_unref(&packet); } } @@ -663,14 +654,6 @@ - (void)videoThreadEntry int64_t now = av_gettime() - _videoClock; int64_t delay = packetTime - now; - if (_statusField != nil) - { - // Show the information... - _statusString = [NSString stringWithFormat: @"Rendering video frame PTS: %ld | Delay: %ld us | %@", - packet.pts, delay, _running ? @"Running" : @"Stopped"]; - [_statusField setStringValue: _statusString]; - } - // Show status on the command line... fprintf(stderr, "[GSMovieView] Rendering video frame PTS: %ld | Delay: %ld us\r", packet.pts, delay); @@ -752,9 +735,19 @@ - (void) decodePacket: (AVPacket *)packet return; } + // Log pts... + fprintf(stderr, "[GSMovieView] Rendering video frame PTS: %ld\r", + packet->pts); + if (_statusField != nil) + { + // Show the information... + _statusString = [NSString stringWithFormat: @"Rendering video frame PTS: %ld | %@", + packet->pts, _running ? @"Running" : @"Stopped"]; + [_statusField setStringValue: _statusString]; + } + // Record last pts... _lastPts = packet->pts; - while (avcodec_receive_frame(_videoCodecCtx, _videoFrame) == 0) { [self renderFrame: _videoFrame]; From 6bce08c9e3fc4810a55bbf095727a12f33799a07 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Tue, 24 Jun 2025 06:18:03 -0400 Subject: [PATCH 69/86] Reimplement as a synchronous process --- Source/GSMovieView.h | 17 +-- Source/GSMovieView.m | 312 +++++++++++++------------------------------ 2 files changed, 96 insertions(+), 233 deletions(-) diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index 7b7bd58a22..15fea28267 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -51,14 +51,11 @@ APPKIT_EXPORT_CLASS @interface GSMovieView : NSMovieView { - NSMutableArray *_videoPackets; - NSThread *_videoThread; - NSThread *_feedThread; NSTimer *_feedTimer; NSImage *_currentFrame; NSString *_statusString; GSAudioPlayer *_audioPlayer; - + AVCodecContext *_videoCodecCtx; AVFrame *_videoFrame; AVFormatContext *_formatCtx; @@ -66,15 +63,13 @@ APPKIT_EXPORT_CLASS struct SwsContext *_swsCtx; AVRational _timeBase; - BOOL _paused; // is the stream paused... - BOOL _running; // is the loop currently running... - BOOL _started; // has the video started... int64_t _videoClock; int _videoStreamIndex; int _audioStreamIndex; int64_t _lastPts; int64_t _savedPts; CGFloat _fps; + BOOL _running; } // Initialization... @@ -82,19 +77,13 @@ APPKIT_EXPORT_CLASS streamIndex: (int)videoStreamIndex; // Submit packets... -- (void) submitPacket: (AVPacket *)packet; - (void) decodePacket: (AVPacket *)packet; // Start and stop... -- (void) startVideo; -- (void) stopVideo; -- (void) setPaused: (BOOL)f; -- (BOOL) isPaused; -- (CGFloat) frameRateForStream: (AVStream *)stream; +- (CGFloat) frameRateForStream; // Main loop to process packets... - (void) renderFrame: (AVFrame *)videoFrame; -- (void) feedVideo; - (BOOL) setup; - (void) loop; - (void) close; diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 74170419f2..c1f63e5f45 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -124,12 +124,9 @@ - (instancetype) initWithFrame: (NSRect)frame if (self != nil) { // Objects... - _currentFrame = nil; - _videoThread = nil; - _feedThread = nil; _audioPlayer = [[GSAudioPlayer alloc] init]; - _videoPackets = [[NSMutableArray alloc] init]; _feedTimer = nil; + _currentFrame = nil; // AV... _videoClock = 0; @@ -142,8 +139,6 @@ - (instancetype) initWithFrame: (NSRect)frame // Flags... _running = NO; // is the thread running? - _started = NO; // have we started processing packets... - _paused = NO; // is the stream paused? // Get notifications and shut down the thread if app is closing. [nc addObserver: self @@ -159,11 +154,6 @@ - (void)dealloc [self stop: nil]; // Cancel thread, dealloc av structs... - if (_feedThread) - { - [_feedThread cancel]; - } - if (_videoFrame) { av_frame_free(&_videoFrame); @@ -180,8 +170,6 @@ - (void)dealloc } // Destroy objects - DESTROY(_feedThread); - DESTROY(_videoPackets); DESTROY(_audioPlayer); DESTROY(_currentFrame); @@ -192,87 +180,58 @@ - (void)dealloc } // New methods... -- (CGFloat) frameRateForStream: (AVStream *)stream +- (CGFloat) frameRateForStream { - if (stream->avg_frame_rate.num > 0 && stream->avg_frame_rate.den > 0) - return av_q2d(stream->avg_frame_rate); + if (_stream->avg_frame_rate.num > 0 && _stream->avg_frame_rate.den > 0) + return av_q2d(_stream->avg_frame_rate); else - return 1.0 / av_q2d(stream->time_base); -} - -- (void) setPaused: (BOOL)f -{ - _paused = f; - [_audioPlayer setPaused: f]; -} - -- (BOOL) isPaused -{ - return _paused; + return (1.0 / av_q2d(_stream->time_base)); } // Notification responses... - (void) handleNotification: (NSNotification *)notification { NSLog(@"[GSMovieView] Shutting down, final pts %ld", _lastPts); + [_feedTimer invalidate]; +} - [_feedThread cancel]; - [_videoThread cancel]; - [_audioPlayer stopAudio]; - [self stopVideo]; +// Overridden methods from the superclass... +- (BOOL) isPlaying +{ + return _running; } -// Private methods... -- (void) _startFeed +- (IBAction) start: (id)sender { if (_running == NO) { - NSTimeInterval fr = (double)(1/[self frameRateForStream: _stream]); + NSTimeInterval fr = (double)(1/[self frameRateForStream]); - NSLog(@"[GSMovieView] framerate = %f", fr); + NSLog(@"[GSMovieView] Starting video | Timestamp: %ld, lastPts = %ld, fr = %f", + av_gettime(), _lastPts, fr); [self setRate: 1.0]; [self setVolume: 1.0]; - _savedPts = 0; + _running = YES; _feedTimer = [NSTimer scheduledTimerWithTimeInterval: fr target: self - selector: @selector(loop) + selector: @selector(decodeAndDisplayNextFrame) userInfo: nil - repeats: YES]; - - // _feedThread = [[NSThread alloc] initWithTarget:self selector:@selector(feedVideo) object:nil]; - // [_feedThread start]; - // [_audioPlayer startAudio]; + repeats: YES]; } } -- (void) _stopFeed +- (IBAction) stop: (id)sender { if (_running == YES) { - _savedPts = _lastPts; - // [_feedThread cancel]; - // [_audioPlayer stopAudio]; + _running = NO; [_feedTimer invalidate]; + NSLog(@"[GSMovieView] Stopping video | Timestamp: %ld, lastPts = %ld", + av_gettime(), _lastPts); } } -// Overridden methods from the superclass... -- (BOOL) isPlaying -{ - return _running; -} - -- (IBAction) start: (id)sender -{ - [self setPaused: NO]; -} - -- (IBAction) stop: (id)sender -{ - [self setPaused: YES]; -} - - (void) setMuted: (BOOL)muted { [super setMuted: muted]; @@ -296,7 +255,7 @@ - (void) setMovie: (NSMovie *)movie { [super setMovie: movie]; [self setup]; - [self _startFeed]; + [self start: nil]; } } @@ -340,22 +299,7 @@ - (IBAction)gotoEnd: (id)sender - (IBAction) stepForward: (id)sender { - int64_t seconds = 2; - int64_t skip = av_rescale_q(seconds, (AVRational){1,1}, _stream->time_base); - int64_t newPts = _lastPts + skip; - if (_paused == NO) - { - _paused = YES; - av_seek_frame(_formatCtx, _videoStreamIndex, newPts, AVSEEK_FLAG_BACKWARD); - avcodec_flush_buffers(_videoCodecCtx); - _paused = NO; - } - else - { - av_seek_frame(_formatCtx, _videoStreamIndex, newPts, AVSEEK_FLAG_BACKWARD); - avcodec_flush_buffers(_videoCodecCtx); - } } - (IBAction) stepBack: (id)sender @@ -368,7 +312,7 @@ - (IBAction) stepBack: (id)sender - (void) updateImage: (NSImage *)image { ASSIGN(_currentFrame, image); - [self setNeedsDisplay:YES]; + [self setNeedsDisplay: YES]; } - (void) drawRect: (NSRect)dirtyRect @@ -431,7 +375,7 @@ - (BOOL) setup // Video stream... if (_videoStreamIndex == -1) { - NSLog(@"[Info] No video stream found. | Timestamp: %ld", av_gettime()); + NSLog(@"[GSMovieView - Info] No video stream found. | Timestamp: %ld", av_gettime()); } else { @@ -442,7 +386,7 @@ - (BOOL) setup // Audio stream... if (_audioStreamIndex == -1) // if we do have an audio stream, initialize it... otherwise log it { - NSLog(@"[Info] No audio stream found. | Timestamp: %ld", av_gettime()); + NSLog(@"[GSMovieView - Info] No audio stream found. | Timestamp: %ld", av_gettime()); } else { @@ -453,7 +397,7 @@ - (BOOL) setup // Video and Audio stream not present... if (_videoStreamIndex == -1 && _audioStreamIndex == -1) { - NSLog(@"[Error] No video or audio stream detected, exiting"); + NSLog(@"[GSMovieView - Error] No video or audio stream detected, exiting"); avformat_close_input(&_formatCtx); return NO; } @@ -463,6 +407,68 @@ - (BOOL) setup return YES; } +- (void) decodeAndDisplayNextFrame +{ + AVPacket packet; + uint8_t *rgbData[1]; + int rgbLineSize[1]; + int width = _videoCodecCtx->width; + int height = _videoCodecCtx->height; + + // av_init_packet(&packet); + packet.data = NULL; + packet.size = 0; + + NSLog(@"Display frame"); + + rgbLineSize[0] = width * 3; + rgbData[0] = (uint8_t *)malloc(height * rgbLineSize[0]); + + while (av_read_frame(_formatCtx, &packet) >= 0) + { + if (!_running) + { + break; + } + + if (packet.stream_index == _videoStreamIndex) + { + avcodec_send_packet(_videoCodecCtx, &packet); + if (avcodec_receive_frame(_videoCodecCtx, _videoFrame) == 0) + { + sws_scale(_swsCtx, + (const uint8_t * const *)_videoFrame->data, + _videoFrame->linesize, + 0, + height, + rgbData, + rgbLineSize); + + NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] + initWithBitmapDataPlanes: &rgbData[0] + pixelsWide: _videoCodecCtx->width + pixelsHigh: _videoCodecCtx->height + bitsPerSample: 8 + samplesPerPixel: 3 + hasAlpha: NO + isPlanar: NO + colorSpaceName: NSCalibratedRGBColorSpace + bytesPerRow: rgbLineSize[0] + bitsPerPixel: 24]; + + NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize(_videoCodecCtx->width, _videoCodecCtx->height)]; + [image addRepresentation:rep]; + + [self performSelectorOnMainThread: @selector(updateImage:) + withObject: image + waitUntilDone: NO]; + break; + } + } + av_packet_unref(&packet); + } +} + - (void) loop { if (_formatCtx != NULL) @@ -476,7 +482,6 @@ - (void) loop [self decodePacket: &packet]; break; } - if (packet.stream_index == _audioStreamIndex) { [_audioPlayer decodePacket: &packet]; @@ -496,22 +501,13 @@ - (void) close } } -- (void) feedVideo -{ - if (_stream != NULL) - { - [self loop]; - [self close]; - } -} - - (void)prepareWithFormatContext: (AVFormatContext *)formatCtx streamIndex: (int)videoStreamIndex { AVCodecParameters *videoPar = NULL; const AVCodec *videoCodec = NULL; _stream = formatCtx->streams[videoStreamIndex]; - _fps = [self frameRateForStream: _stream]; + _fps = [self frameRateForStream]; videoPar = _stream->codecpar; videoCodec = avcodec_find_decoder(videoPar->codec_id); @@ -540,142 +536,20 @@ - (void)prepareWithFormatContext: (AVFormatContext *)formatCtx streamIndex: (int videoPar->height, AV_PIX_FMT_RGB24, SWS_BILINEAR, - NULL, NULL, NULL); + NULL, + NULL, + NULL); _timeBase = formatCtx->streams[videoStreamIndex]->time_base; - _videoPackets = [[NSMutableArray alloc] init]; _videoClock = av_gettime(); _running = NO; } -- (void) startVideo -{ - NSLog(@"[GSMovieView] Starting video thread | Timestamp: %ld, lastPts = %ld", - av_gettime(), _lastPts); - if (!_running) - { - _running = YES; - _videoThread = [[NSThread alloc] initWithTarget:self - selector:@selector(videoThreadEntry) - object:nil]; - [_videoThread start]; - } -} - -- (void) stopVideo -{ - NSLog(@"[GSMovieView] Stopping video thread | Timestamp: %ld, lastPts = %ld", - av_gettime(), _lastPts); - if (_running) - { - _running = NO; - - [_videoThread cancel]; - while (![_videoThread isFinished]) - { - usleep(1000); - } - - DESTROY(_videoThread); - avformat_close_input(&_formatCtx); - - _savedPts = _lastPts; - _lastPts = 0; - } -} - - (void) setPlaying: (BOOL)f { _running = f; } -- (void)submitPacket: (AVPacket *)packet -{ - NSDictionary *dict = NSDictionaryFromAVPacket(packet); - - if (_paused) - { - NSLog(@"Submitted packet..."); - } - - @synchronized (_videoPackets) - { - [_videoPackets addObject: dict]; - } -} - -- (void)videoThreadEntry -{ - while (_running) - { - // Stop reading packets while paused... - if (_paused == YES) - { - usleep(10000); // 10ms pause - continue; // start the loop again... - } - - // Create pool... - CREATE_AUTORELEASE_POOL(pool); - { - NSDictionary *dict = nil; - - // Pop the video packet off _videoPackets, sync on - // the array. - @synchronized (_videoPackets) - { - if ([_videoPackets count] > 0) - { - dict = RETAIN([_videoPackets objectAtIndex: 0]); - [_videoPackets removeObjectAtIndex: 0]; - } - } - - // If the dict is present and the thread is started, get - // the clock. - if (!_started && dict) - { - _videoClock = av_gettime(); - _started = YES; - } - - // If dict is not nil, decode it and get the frame... - if (dict) - { - AVPacket packet = AVPacketFromNSDictionary(dict); - - // If the current pts is at or after the saved, - // then alow it to be decoded and displayed... - if (packet.pts >= _savedPts) - { - int64_t packetTime = av_rescale_q(packet.pts, - _timeBase, - (AVRational){1, 1000000}); - int64_t now = av_gettime() - _videoClock; - int64_t delay = packetTime - now; - - // Show status on the command line... - fprintf(stderr, "[GSMovieView] Rendering video frame PTS: %ld | Delay: %ld us\r", - packet.pts, delay); - if (delay > 0) - { - usleep((useconds_t)delay); - } - - // Decode the packet, display it and play the sound... - [self decodePacket: &packet]; - RELEASE(dict); - } - else - { - usleep(1000); - } - } - } - RELEASE(pool); - } -} - - (void) renderFrame: (AVFrame *)videoFrame { uint8_t *rgbData[1]; From 14c894faf56f5cc8246586048bfa3c9cb3f25bcd Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Tue, 24 Jun 2025 06:38:31 -0400 Subject: [PATCH 70/86] Add else for audio --- Source/GSMovieView.m | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index c1f63e5f45..fb3dbda7b1 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -419,8 +419,6 @@ - (void) decodeAndDisplayNextFrame packet.data = NULL; packet.size = 0; - NSLog(@"Display frame"); - rgbLineSize[0] = width * 3; rgbData[0] = (uint8_t *)malloc(height * rgbLineSize[0]); @@ -465,7 +463,12 @@ - (void) decodeAndDisplayNextFrame break; } } - av_packet_unref(&packet); + else if (packet.stream_index == _audioStreamIndex) + { + NSLog(@"Audio packet..."); + } + + av_packet_unref(&packet); } } From 56eec2060291ca0e6006c1ddda5d182cd7a52217 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Tue, 24 Jun 2025 23:42:48 -0400 Subject: [PATCH 71/86] Re-integrate sound, video, make synchronous --- Source/GSAudioPlayer.h | 23 ++---- Source/GSAudioPlayer.m | 132 +-------------------------------- Source/GSMovieView.h | 1 - Source/GSMovieView.m | 161 ++++++++++++----------------------------- 4 files changed, 55 insertions(+), 262 deletions(-) diff --git a/Source/GSAudioPlayer.h b/Source/GSAudioPlayer.h index c7684230d9..192de4738b 100644 --- a/Source/GSAudioPlayer.h +++ b/Source/GSAudioPlayer.h @@ -46,6 +46,7 @@ #include #include +@class NSDictionary; @class NSMutableArray; @class NSThread; @@ -59,38 +60,24 @@ ao_sample_format _aoFmt; int64_t _audioClock; AVRational _timeBase; - float _volume; /* 0.0 to 1.0 */ - unsigned int _loopMode:3; - - NSMutableArray *_audioPackets; - NSThread *_audioThread; + float _volume; /* 0.0 to 1.0 */ BOOL _running; - BOOL _started; BOOL _muted; - BOOL _paused; } - (void) prepareWithFormatContext: (AVFormatContext *)formatCtx streamIndex: (int)audioStreamIndex; +// Decode and play the packet... - (void) decodePacket: (AVPacket *)packet; -- (void) submitPacket: (AVPacket *)packet; -- (void) startAudio; -- (void) stopAudio; +- (void) decodeDictionary: (NSDictionary *)dict; +// Controls... - (float) volume; - (void) setVolume: (float)volume; - -- (NSQTMovieLoopMode) loopMode; -- (void) setLoopMode: (NSQTMovieLoopMode)mode; - - (void) setMuted: (BOOL)muted; - (BOOL) isMuted; -- (void) setPaused: (BOOL)f; -- (BOOL) isPaused; -- (void) setPlaying: (BOOL)f; -- (BOOL) isPlaying; @end diff --git a/Source/GSAudioPlayer.m b/Source/GSAudioPlayer.m index d016020cd5..9e6778a72e 100644 --- a/Source/GSAudioPlayer.m +++ b/Source/GSAudioPlayer.m @@ -39,21 +39,13 @@ - (instancetype) init _audioFrame = NULL; _swrCtx = NULL; _audioClock = 0; - _audioPackets = nil; - _audioThread = nil; - _running = NO; _volume = 1.0; - _started = NO; - _paused = NO; - _loopMode = NSQTMovieNormalPlayback; } return self; } - (void)dealloc { - [self stopAudio]; - if (_audioFrame) { av_frame_free(&_audioFrame); @@ -74,42 +66,10 @@ - (void)dealloc ao_close(_aoDev); } - RELEASE(_audioPackets); - ao_shutdown(); [super dealloc]; } -- (void) setPaused: (BOOL)f; -{ - _paused = f; -} - -- (BOOL) isPaused -{ - return _paused; -} - -- (void) setPlaying: (BOOL)f -{ - _running = f; -} - -- (BOOL) isPlaying -{ - return _running; -} - -- (NSQTMovieLoopMode) loopMode -{ - return _loopMode; -} - -- (void) setLoopMode: (NSQTMovieLoopMode)mode -{ - _loopMode = mode; -} - - (void) prepareWithFormatContext: (AVFormatContext *)formatCtx streamIndex: (int)audioStreamIndex { @@ -161,65 +121,9 @@ - (void) prepareWithFormatContext: (AVFormatContext *)formatCtx _aoDev = ao_open_live(driver, &_aoFmt, NULL); _timeBase = formatCtx->streams[audioStreamIndex]->time_base; _audioClock = av_gettime(); - _audioPackets = [[NSMutableArray alloc] init]; _running = YES; } -- (void)audioThreadEntry -{ - while (_running) - { - // Stop reading packets while paused... - if (_paused == YES) - { - usleep(10000); // 10ms pause - continue; // start the loop again... - } - - // create pool... - CREATE_AUTORELEASE_POOL(pool); - { - NSDictionary *dict = nil; - - @synchronized (_audioPackets) - { - if ([_audioPackets count] > 0) - { - dict = [[_audioPackets objectAtIndex:0] retain]; - [_audioPackets removeObjectAtIndex:0]; - } - } - - if (!_started && dict) - { - _audioClock = av_gettime(); - _started = YES; - } - - if (dict) - { - AVPacket packet = AVPacketFromNSDictionary(dict); - int64_t packetTime = av_rescale_q(packet.pts, _timeBase, (AVRational){1, 1000000}); - int64_t now = av_gettime() - _audioClock; - int64_t delay = packetTime - now; - - if (delay > 0) - { - usleep((useconds_t)delay); // + 50000); - } - - [self decodePacket:&packet]; - [dict release]; - } - else - { - usleep(1000); - } - } - RELEASE(pool); - } -} - - (void)decodePacket: (AVPacket *)packet { if (!_audioCodecCtx || !_swrCtx || !_aoDev) @@ -269,40 +173,10 @@ - (void)decodePacket: (AVPacket *)packet } } -- (void) submitPacket: (AVPacket *)packet -{ - NSDictionary *dict = NSDictionaryFromAVPacket(packet); - - if (_paused) - { - NSLog(@"Submitted audio packet..."); - } - - @synchronized (_audioPackets) - { - [_audioPackets addObject: dict]; - } -} - -- (void) startAudio +- (void) decodeDictionary: (NSDictionary *)dict { - _running = YES; - NSLog(@"[GSAudioPlayer] Starting audio thread | Timestamp: %ld", av_gettime()); - _audioThread = [[NSThread alloc] initWithTarget:self selector:@selector(audioThreadEntry) object:nil]; - [_audioThread start]; -} - -- (void) stopAudio -{ - _running = NO; - [_audioThread cancel]; - - while ([_audioThread isFinished] == NO) - { - usleep(1000); - } - - DESTROY(_audioThread); + AVPacket packet = AVPacketFromNSDictionary(dict); + [self decodePacket: &packet]; } - (void) setVolume: (float)volume diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index 15fea28267..20e76795d1 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -85,7 +85,6 @@ APPKIT_EXPORT_CLASS // Main loop to process packets... - (void) renderFrame: (AVFrame *)videoFrame; - (BOOL) setup; -- (void) loop; - (void) close; @end diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index fb3dbda7b1..ae52a1f164 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -127,7 +127,7 @@ - (instancetype) initWithFrame: (NSRect)frame _audioPlayer = [[GSAudioPlayer alloc] init]; _feedTimer = nil; _currentFrame = nil; - + // AV... _videoClock = 0; _videoCodecCtx = NULL; @@ -139,7 +139,7 @@ - (instancetype) initWithFrame: (NSRect)frame // Flags... _running = NO; // is the thread running? - + // Get notifications and shut down the thread if app is closing. [nc addObserver: self selector: @selector(handleNotification:) @@ -172,7 +172,7 @@ - (void)dealloc // Destroy objects DESTROY(_audioPlayer); DESTROY(_currentFrame); - + // Unsubscribe to NSNotification [nc removeObserver: self]; @@ -208,16 +208,16 @@ - (IBAction) start: (id)sender NSTimeInterval fr = (double)(1/[self frameRateForStream]); NSLog(@"[GSMovieView] Starting video | Timestamp: %ld, lastPts = %ld, fr = %f", - av_gettime(), _lastPts, fr); + av_gettime(), _lastPts, fr); [self setRate: 1.0]; [self setVolume: 1.0]; - + _running = YES; _feedTimer = [NSTimer scheduledTimerWithTimeInterval: fr target: self selector: @selector(decodeAndDisplayNextFrame) userInfo: nil - repeats: YES]; + repeats: YES]; } } @@ -228,7 +228,7 @@ - (IBAction) stop: (id)sender _running = NO; [_feedTimer invalidate]; NSLog(@"[GSMovieView] Stopping video | Timestamp: %ld, lastPts = %ld", - av_gettime(), _lastPts); + av_gettime(), _lastPts); } } @@ -262,16 +262,16 @@ - (void) setMovie: (NSMovie *)movie - (NSRect) movieRect { NSRect result = NSZeroRect; - + if (_stream != NULL) { // Retrieve codec parameters AVCodecParameters* codecpar = _stream->codecpar; - + // These are your video dimensions: CGFloat width = (CGFloat)(codecpar->width); CGFloat height = (CGFloat)(codecpar->height); - + result = NSMakeRect(0.0, 0.0, width, height); } @@ -327,7 +327,7 @@ - (void) drawRect: (NSRect)dirtyRect - (BOOL) setup { NSMovie *movie = [self movie]; - + if (movie != nil) { NSURL *url = [movie URL]; @@ -407,6 +407,10 @@ - (BOOL) setup return YES; } +- (void) decodePacket: (AVPacket *)packet +{ +} + - (void) decodeAndDisplayNextFrame { AVPacket packet; @@ -421,14 +425,31 @@ - (void) decodeAndDisplayNextFrame rgbLineSize[0] = width * 3; rgbData[0] = (uint8_t *)malloc(height * rgbLineSize[0]); - + while (av_read_frame(_formatCtx, &packet) >= 0) { if (!_running) { break; } - + + if (packet.flags & AV_PKT_FLAG_CORRUPT) + { + NSLog(@"Skipping corrupt video packet"); + return; + } + + // Log pts... + fprintf(stderr, "[GSMovieView] Rendering video frame PTS: %ld\r", + packet.pts); + if (_statusField != nil) + { + // Show the information... + _statusString = [NSString stringWithFormat: @"Rendering video frame PTS: %ld | %@", + packet.pts, _running ? @"Running" : @"Stopped"]; + [_statusField setStringValue: _statusString]; + } + if (packet.stream_index == _videoStreamIndex) { avcodec_send_packet(_videoCodecCtx, &packet); @@ -455,47 +476,33 @@ - (void) decodeAndDisplayNextFrame bitsPerPixel: 24]; NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize(_videoCodecCtx->width, _videoCodecCtx->height)]; - [image addRepresentation:rep]; + [image addRepresentation: rep]; [self performSelectorOnMainThread: @selector(updateImage:) withObject: image waitUntilDone: NO]; + + AUTORELEASE(image); + AUTORELEASE(rep); + break; } } else if (packet.stream_index == _audioStreamIndex) { - NSLog(@"Audio packet..."); + NSDictionary *dict = NSDictionaryFromAVPacket(&packet); + + [NSThread detachNewThreadSelector: @selector(decodeDictionary:) + toTarget: _audioPlayer + withObject: dict]; + // [_audioPlayer decodePacket: &packet]; + break; } av_packet_unref(&packet); } } -- (void) loop -{ - if (_formatCtx != NULL) - { - AVPacket packet; - - while (av_read_frame(_formatCtx, &packet) >= 0) - { - if (packet.stream_index == _videoStreamIndex) - { - [self decodePacket: &packet]; - break; - } - if (packet.stream_index == _audioStreamIndex) - { - [_audioPlayer decodePacket: &packet]; - break; - } - } - - av_packet_unref(&packet); - } -} - - (void) close { if (_formatCtx != NULL) @@ -510,7 +517,7 @@ - (void)prepareWithFormatContext: (AVFormatContext *)formatCtx streamIndex: (int const AVCodec *videoCodec = NULL; _stream = formatCtx->streams[videoStreamIndex]; - _fps = [self frameRateForStream]; + _fps = [self frameRateForStream]; videoPar = _stream->codecpar; videoCodec = avcodec_find_decoder(videoPar->codec_id); @@ -555,80 +562,6 @@ - (void) setPlaying: (BOOL)f - (void) renderFrame: (AVFrame *)videoFrame { - uint8_t *rgbData[1]; - int rgbLineSize[1]; - int width = _videoCodecCtx->width; - int height = _videoCodecCtx->height; - - rgbLineSize[0] = width * 3; - rgbData[0] = (uint8_t *)malloc(height * rgbLineSize[0]); - - sws_scale(_swsCtx, - (const uint8_t * const *)videoFrame->data, - videoFrame->linesize, - 0, - height, - rgbData, - rgbLineSize); - - NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] - initWithBitmapDataPlanes: &rgbData[0] - pixelsWide: width - pixelsHigh: height - bitsPerSample: 8 - samplesPerPixel: 3 - hasAlpha: NO - isPlanar: NO - colorSpaceName: NSCalibratedRGBColorSpace - bytesPerRow: rgbLineSize[0] - bitsPerPixel: 24]; - - NSImage *image = [[NSImage alloc] initWithSize: NSMakeSize(width, height)]; - [image addRepresentation: bitmap]; - [self performSelectorOnMainThread: @selector(updateImage:) - withObject: image - waitUntilDone: NO]; - - RELEASE(image); - RELEASE(bitmap); - free(rgbData[0]); -} - -- (void) decodePacket: (AVPacket *)packet -{ - if (!_videoCodecCtx || !_swsCtx) - { - return; - } - - if (avcodec_send_packet(_videoCodecCtx, packet) < 0) - { - return; - } - - if (packet->flags & AV_PKT_FLAG_CORRUPT) - { - NSLog(@"Skipping corrupt video packet"); - return; - } - - // Log pts... - fprintf(stderr, "[GSMovieView] Rendering video frame PTS: %ld\r", - packet->pts); - if (_statusField != nil) - { - // Show the information... - _statusString = [NSString stringWithFormat: @"Rendering video frame PTS: %ld | %@", - packet->pts, _running ? @"Running" : @"Stopped"]; - [_statusField setStringValue: _statusString]; - } - - // Record last pts... - _lastPts = packet->pts; - while (avcodec_receive_frame(_videoCodecCtx, _videoFrame) == 0) - { - [self renderFrame: _videoFrame]; - } } @end From e984fbdb946aadcee009e0f4ef84eadff3a08d08 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Wed, 25 Jun 2025 05:21:51 -0400 Subject: [PATCH 72/86] Refactor into methods --- Source/GSAudioPlayer.h | 4 +- Source/GSAudioPlayer.m | 14 +++-- Source/GSMovieView.h | 3 +- Source/GSMovieView.m | 132 ++++++++++++++++++++++++----------------- 4 files changed, 90 insertions(+), 63 deletions(-) diff --git a/Source/GSAudioPlayer.h b/Source/GSAudioPlayer.h index 192de4738b..c93641b181 100644 --- a/Source/GSAudioPlayer.h +++ b/Source/GSAudioPlayer.h @@ -70,8 +70,8 @@ streamIndex: (int)audioStreamIndex; // Decode and play the packet... -- (void) decodePacket: (AVPacket *)packet; -- (void) decodeDictionary: (NSDictionary *)dict; +- (BOOL) decodePacket: (AVPacket *)packet; +- (BOOL) decodeDictionary: (NSDictionary *)dict; // Controls... - (float) volume; diff --git a/Source/GSAudioPlayer.m b/Source/GSAudioPlayer.m index 9e6778a72e..927ec5b2c5 100644 --- a/Source/GSAudioPlayer.m +++ b/Source/GSAudioPlayer.m @@ -124,22 +124,22 @@ - (void) prepareWithFormatContext: (AVFormatContext *)formatCtx _running = YES; } -- (void)decodePacket: (AVPacket *)packet +- (BOOL) decodePacket: (AVPacket *)packet { if (!_audioCodecCtx || !_swrCtx || !_aoDev) { - return; + return NO; } if (avcodec_send_packet(_audioCodecCtx, packet) < 0) { - return; + return NO; } if (packet->flags & AV_PKT_FLAG_CORRUPT) { NSLog(@"Skipping corrupt audio packet"); - return; + return NO; } while (avcodec_receive_frame(_audioCodecCtx, _audioFrame) == 0) @@ -171,12 +171,14 @@ - (void)decodePacket: (AVPacket *)packet ao_play(_aoDev, (char *) outBuf, outBytes); free(outBuf); } + + return YES; } -- (void) decodeDictionary: (NSDictionary *)dict +- (BOOL) decodeDictionary: (NSDictionary *)dict { AVPacket packet = AVPacketFromNSDictionary(dict); - [self decodePacket: &packet]; + return [self decodePacket: &packet]; } - (void) setVolume: (float)volume diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index 20e76795d1..1dd4e5603b 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -77,7 +77,8 @@ APPKIT_EXPORT_CLASS streamIndex: (int)videoStreamIndex; // Submit packets... -- (void) decodePacket: (AVPacket *)packet; +- (BOOL) decodePacket: (AVPacket *)packet; +- (BOOL) decodeDictionary: (NSDictionary *)dict; // Start and stop... - (CGFloat) frameRateForStream; diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index ae52a1f164..178853b7e6 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -407,63 +407,55 @@ - (BOOL) setup return YES; } -- (void) decodePacket: (AVPacket *)packet +- (BOOL) decodePacket: (AVPacket *)packet { -} - -- (void) decodeAndDisplayNextFrame -{ - AVPacket packet; uint8_t *rgbData[1]; int rgbLineSize[1]; int width = _videoCodecCtx->width; int height = _videoCodecCtx->height; - // av_init_packet(&packet); - packet.data = NULL; - packet.size = 0; - + // Get the image data from the packet... rgbLineSize[0] = width * 3; rgbData[0] = (uint8_t *)malloc(height * rgbLineSize[0]); - - while (av_read_frame(_formatCtx, &packet) >= 0) + + if (!_videoCodecCtx || !_swsCtx) { - if (!_running) - { - break; - } + return NO; + } - if (packet.flags & AV_PKT_FLAG_CORRUPT) - { - NSLog(@"Skipping corrupt video packet"); - return; - } + if (avcodec_send_packet(_videoCodecCtx, packet) < 0) + { + return NO; + } - // Log pts... - fprintf(stderr, "[GSMovieView] Rendering video frame PTS: %ld\r", - packet.pts); - if (_statusField != nil) - { - // Show the information... - _statusString = [NSString stringWithFormat: @"Rendering video frame PTS: %ld | %@", - packet.pts, _running ? @"Running" : @"Stopped"]; - [_statusField setStringValue: _statusString]; - } + if (packet->flags & AV_PKT_FLAG_CORRUPT) + { + NSLog(@"Skipping corrupt audio packet"); + return NO; + } - if (packet.stream_index == _videoStreamIndex) - { - avcodec_send_packet(_videoCodecCtx, &packet); - if (avcodec_receive_frame(_videoCodecCtx, _videoFrame) == 0) - { - sws_scale(_swsCtx, - (const uint8_t * const *)_videoFrame->data, - _videoFrame->linesize, - 0, - height, - rgbData, - rgbLineSize); - - NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] + // Log pts... + fprintf(stderr, "[GSMovieView] Rendering video frame PTS: %ld\r", + packet->pts); + if (_statusField != nil) + { + // Show the information... + _statusString = [NSString stringWithFormat: @"Rendering video frame PTS: %ld | %@", + packet->pts, _running ? @"Running" : @"Stopped"]; + [_statusField setStringValue: _statusString]; + } + + while (avcodec_receive_frame(_videoCodecCtx, _videoFrame) == 0) + { + sws_scale(_swsCtx, + (const uint8_t * const *)_videoFrame->data, + _videoFrame->linesize, + 0, + height, + rgbData, + rgbLineSize); + + NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: &rgbData[0] pixelsWide: _videoCodecCtx->width pixelsHigh: _videoCodecCtx->height @@ -475,18 +467,50 @@ - (void) decodeAndDisplayNextFrame bytesPerRow: rgbLineSize[0] bitsPerPixel: 24]; - NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize(_videoCodecCtx->width, _videoCodecCtx->height)]; - [image addRepresentation: rep]; + NSImage *image = [[NSImage alloc] initWithSize: NSMakeSize(_videoCodecCtx->width, + _videoCodecCtx->height)]; + [image addRepresentation: rep]; + [self performSelectorOnMainThread: @selector(updateImage:) + withObject: image + waitUntilDone: NO]; + + AUTORELEASE(image); + AUTORELEASE(rep); + } - [self performSelectorOnMainThread: @selector(updateImage:) - withObject: image - waitUntilDone: NO]; + return YES; +} - AUTORELEASE(image); - AUTORELEASE(rep); +- (BOOL) decodeDictionary: (NSDictionary *)dict +{ + AVPacket packet = AVPacketFromNSDictionary(dict); + return [self decodePacket: &packet]; +} - break; - } +- (void) decodeAndDisplayNextFrame +{ + AVPacket packet; + + // av_init_packet(&packet); + packet.data = NULL; + packet.size = 0; + + while (av_read_frame(_formatCtx, &packet) >= 0) + { + if (!_running) + { + break; + } + + if (packet.flags & AV_PKT_FLAG_CORRUPT) + { + NSLog(@"Skipping corrupt video packet"); + break; + } + + if (packet.stream_index == _videoStreamIndex) + { + [self decodePacket: &packet]; } else if (packet.stream_index == _audioStreamIndex) { From 0eaf4d965d8b8f7f1263a30c65cd391dbcef50d4 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Wed, 25 Jun 2025 05:32:58 -0400 Subject: [PATCH 73/86] Refactor image rendering into renderFrame: --- Source/GSMovieView.m | 73 ++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 178853b7e6..2c5cb79808 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -407,7 +407,7 @@ - (BOOL) setup return YES; } -- (BOOL) decodePacket: (AVPacket *)packet +- (void) renderFrame: (AVFrame *)videoFrame { uint8_t *rgbData[1]; int rgbLineSize[1]; @@ -417,7 +417,40 @@ - (BOOL) decodePacket: (AVPacket *)packet // Get the image data from the packet... rgbLineSize[0] = width * 3; rgbData[0] = (uint8_t *)malloc(height * rgbLineSize[0]); - + + sws_scale(_swsCtx, + (const uint8_t * const *)_videoFrame->data, + _videoFrame->linesize, + 0, + height, + rgbData, + rgbLineSize); + + NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] + initWithBitmapDataPlanes: &rgbData[0] + pixelsWide: _videoCodecCtx->width + pixelsHigh: _videoCodecCtx->height + bitsPerSample: 8 + samplesPerPixel: 3 + hasAlpha: NO + isPlanar: NO + colorSpaceName: NSCalibratedRGBColorSpace + bytesPerRow: rgbLineSize[0] + bitsPerPixel: 24]; + + NSImage *image = [[NSImage alloc] initWithSize: NSMakeSize(_videoCodecCtx->width, + _videoCodecCtx->height)]; + [image addRepresentation: rep]; + [self performSelectorOnMainThread: @selector(updateImage:) + withObject: image + waitUntilDone: NO]; + + AUTORELEASE(image); + AUTORELEASE(rep); +} + +- (BOOL) decodePacket: (AVPacket *)packet +{ if (!_videoCodecCtx || !_swsCtx) { return NO; @@ -444,38 +477,10 @@ - (BOOL) decodePacket: (AVPacket *)packet packet->pts, _running ? @"Running" : @"Stopped"]; [_statusField setStringValue: _statusString]; } - + while (avcodec_receive_frame(_videoCodecCtx, _videoFrame) == 0) { - sws_scale(_swsCtx, - (const uint8_t * const *)_videoFrame->data, - _videoFrame->linesize, - 0, - height, - rgbData, - rgbLineSize); - - NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] - initWithBitmapDataPlanes: &rgbData[0] - pixelsWide: _videoCodecCtx->width - pixelsHigh: _videoCodecCtx->height - bitsPerSample: 8 - samplesPerPixel: 3 - hasAlpha: NO - isPlanar: NO - colorSpaceName: NSCalibratedRGBColorSpace - bytesPerRow: rgbLineSize[0] - bitsPerPixel: 24]; - - NSImage *image = [[NSImage alloc] initWithSize: NSMakeSize(_videoCodecCtx->width, - _videoCodecCtx->height)]; - [image addRepresentation: rep]; - [self performSelectorOnMainThread: @selector(updateImage:) - withObject: image - waitUntilDone: NO]; - - AUTORELEASE(image); - AUTORELEASE(rep); + [self renderFrame: _videoFrame]; } return YES; @@ -584,8 +589,4 @@ - (void) setPlaying: (BOOL)f _running = f; } -- (void) renderFrame: (AVFrame *)videoFrame -{ -} - @end From 64f8a6a7c172e5ef3d466e30e7e27e9ea50f3994 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Wed, 25 Jun 2025 06:14:52 -0400 Subject: [PATCH 74/86] Move decoding into a thread for each packet --- Source/GSMovieView.m | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 2c5cb79808..7ff5618712 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -502,6 +502,8 @@ - (void) decodeAndDisplayNextFrame while (av_read_frame(_formatCtx, &packet) >= 0) { + NSDictionary *dict = nil; + if (!_running) { break; @@ -513,18 +515,19 @@ - (void) decodeAndDisplayNextFrame break; } + dict = NSDictionaryFromAVPacket(&packet); if (packet.stream_index == _videoStreamIndex) { - [self decodePacket: &packet]; + [NSThread detachNewThreadSelector: @selector(decodeDictionary:) + toTarget: self + withObject: dict]; + break; } else if (packet.stream_index == _audioStreamIndex) { - NSDictionary *dict = NSDictionaryFromAVPacket(&packet); - [NSThread detachNewThreadSelector: @selector(decodeDictionary:) toTarget: _audioPlayer withObject: dict]; - // [_audioPlayer decodePacket: &packet]; break; } From 0fde3d5cb4d3e8f7b184d5baf733c3e6278d2cbc Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Thu, 26 Jun 2025 07:06:56 -0400 Subject: [PATCH 75/86] Add code to decode to data for audio --- Source/GSAudioPlayer.h | 2 ++ Source/GSAudioPlayer.m | 77 ++++++++++++++++++++++++++++-------------- 2 files changed, 54 insertions(+), 25 deletions(-) diff --git a/Source/GSAudioPlayer.h b/Source/GSAudioPlayer.h index c93641b181..d7fb162fdc 100644 --- a/Source/GSAudioPlayer.h +++ b/Source/GSAudioPlayer.h @@ -70,8 +70,10 @@ streamIndex: (int)audioStreamIndex; // Decode and play the packet... +- (NSData *) decodePacketToData: (AVPacket *)packet; - (BOOL) decodePacket: (AVPacket *)packet; - (BOOL) decodeDictionary: (NSDictionary *)dict; +- (void) playData: (NSData *)data; // Controls... - (float) volume; diff --git a/Source/GSAudioPlayer.m b/Source/GSAudioPlayer.m index 927ec5b2c5..9cd6857e7f 100644 --- a/Source/GSAudioPlayer.m +++ b/Source/GSAudioPlayer.m @@ -124,24 +124,26 @@ - (void) prepareWithFormatContext: (AVFormatContext *)formatCtx _running = YES; } -- (BOOL) decodePacket: (AVPacket *)packet +- (NSData *) decodePacketToData: (AVPacket *)packet { if (!_audioCodecCtx || !_swrCtx || !_aoDev) { - return NO; + return nil; } - if (avcodec_send_packet(_audioCodecCtx, packet) < 0) + if (packet->flags & AV_PKT_FLAG_CORRUPT) { - return NO; + NSLog(@"Skipping corrupt audio packet"); + return nil; } - if (packet->flags & AV_PKT_FLAG_CORRUPT) + if (avcodec_send_packet(_audioCodecCtx, packet) < 0) { - NSLog(@"Skipping corrupt audio packet"); - return NO; + return nil; } + NSMutableData *decodedData = [NSMutableData data]; + while (avcodec_receive_frame(_audioCodecCtx, _audioFrame) == 0) { int outSamples = _audioFrame->nb_samples; @@ -149,30 +151,47 @@ - (BOOL) decodePacket: (AVPacket *)packet uint8_t *outBuf = (uint8_t *) malloc(outBytes); uint8_t *outPtrs[] = { outBuf }; - swr_convert(_swrCtx, outPtrs, outSamples, - (const uint8_t **) _audioFrame->data, - outSamples); + swr_convert(_swrCtx, + outPtrs, + outSamples, + (const uint8_t **) _audioFrame->data, + outSamples); - // Apply volume - int16_t *samples = (int16_t *)outBuf; + int16_t *samples = (int16_t *) outBuf; int i = 0; for (i = 0; i < outBytes / 2; ++i) - { - if ([self isMuted]) - { - samples[i] = 0.0; - } - else - { - samples[i] = samples[i] * _volume; - } - } - - ao_play(_aoDev, (char *) outBuf, outBytes); + { + if ([self isMuted]) + { + samples[i] = 0; + } + else + { + samples[i] = (int16_t)(samples[i] * _volume); + } + } + + [decodedData appendBytes: outBuf length: outBytes]; free(outBuf); } - return YES; + return ([decodedData length] > 0) ? decodedData : nil; +} + +- (BOOL) decodePacket: (AVPacket *)packet +{ + NSData *data = [self decodePacketToData: packet]; + BOOL result = NO; + + if (data != nil) + { + RETAIN(data); + [self playData: data]; + result = YES; + RELEASE(data); + } + + return result; } - (BOOL) decodeDictionary: (NSDictionary *)dict @@ -181,6 +200,14 @@ - (BOOL) decodeDictionary: (NSDictionary *)dict return [self decodePacket: &packet]; } +- (void) playData: (NSData *)data +{ + char *outBuf = (char *)[data bytes]; + int outBytes = [data length]; + + ao_play(_aoDev, (char *) outBuf, outBytes); +} + - (void) setVolume: (float)volume { if (volume < 0.0) From 098e0d8c54e45fb9cbe729ada465342738ce2383 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Thu, 26 Jun 2025 22:10:00 -0400 Subject: [PATCH 76/86] Add cache ivars --- Source/GSMovieView.h | 9 +++++++-- Source/GSMovieView.m | 23 +++++++++++++++-------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index 1dd4e5603b..13ac686db9 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -44,9 +44,10 @@ #include #include +@class GSAudioPlayer; @class NSImage; +@class NSMutableArray; @class NSTimer; -@class GSAudioPlayer; APPKIT_EXPORT_CLASS @interface GSMovieView : NSMovieView @@ -70,6 +71,10 @@ APPKIT_EXPORT_CLASS int64_t _savedPts; CGFloat _fps; BOOL _running; + + // buffers + NSMutableArray *_videoBuffer; + NSMutableArray *_audioBuffer; } // Initialization... @@ -84,7 +89,7 @@ APPKIT_EXPORT_CLASS - (CGFloat) frameRateForStream; // Main loop to process packets... -- (void) renderFrame: (AVFrame *)videoFrame; +- (NSImage *) renderFrame: (AVFrame *)videoFrame; - (BOOL) setup; - (void) close; diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 7ff5618712..ba75625bd4 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -140,6 +140,10 @@ - (instancetype) initWithFrame: (NSRect)frame // Flags... _running = NO; // is the thread running? + // buffers... + _videoBuffer = [[NSMutableArray alloc] init]; + _audioBuffer = [[NSMutableArray alloc] init]; + // Get notifications and shut down the thread if app is closing. [nc addObserver: self selector: @selector(handleNotification:) @@ -172,7 +176,9 @@ - (void)dealloc // Destroy objects DESTROY(_audioPlayer); DESTROY(_currentFrame); - + DESTROY(_videoBuffer); + DESTROY(_audioBuffer); + // Unsubscribe to NSNotification [nc removeObserver: self]; @@ -407,7 +413,7 @@ - (BOOL) setup return YES; } -- (void) renderFrame: (AVFrame *)videoFrame +- (NSImage *) renderFrame: (AVFrame *)videoFrame { uint8_t *rgbData[1]; int rgbLineSize[1]; @@ -441,12 +447,9 @@ - (void) renderFrame: (AVFrame *)videoFrame NSImage *image = [[NSImage alloc] initWithSize: NSMakeSize(_videoCodecCtx->width, _videoCodecCtx->height)]; [image addRepresentation: rep]; - [self performSelectorOnMainThread: @selector(updateImage:) - withObject: image - waitUntilDone: NO]; - - AUTORELEASE(image); AUTORELEASE(rep); + + return image; } - (BOOL) decodePacket: (AVPacket *)packet @@ -480,7 +483,11 @@ - (BOOL) decodePacket: (AVPacket *)packet while (avcodec_receive_frame(_videoCodecCtx, _videoFrame) == 0) { - [self renderFrame: _videoFrame]; + NSImage *image = [self renderFrame: _videoFrame]; + [self performSelectorOnMainThread: @selector(updateImage:) + withObject: image + waitUntilDone: NO]; + AUTORELEASE(image); } return YES; From 7cd00aa620d62b05bd5865470171c904d940741a Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Thu, 26 Jun 2025 23:31:22 -0400 Subject: [PATCH 77/86] Remove uneedeed code --- Source/GSMovieView.m | 1 - 1 file changed, 1 deletion(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index ba75625bd4..6a02951e01 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -503,7 +503,6 @@ - (void) decodeAndDisplayNextFrame { AVPacket packet; - // av_init_packet(&packet); packet.data = NULL; packet.size = 0; From 57892839ae9f462268b54ab6cc168df1dabcbae3 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Thu, 26 Jun 2025 23:38:31 -0400 Subject: [PATCH 78/86] Factor out rendering image to other methods --- Source/GSMovieView.m | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 6a02951e01..d435564ac6 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -452,22 +452,22 @@ - (NSImage *) renderFrame: (AVFrame *)videoFrame return image; } -- (BOOL) decodePacket: (AVPacket *)packet +- (NSImage *) decodePacketToImage: (AVPacket *)packet { if (!_videoCodecCtx || !_swsCtx) { - return NO; + return nil; } if (avcodec_send_packet(_videoCodecCtx, packet) < 0) { - return NO; + return nil; } if (packet->flags & AV_PKT_FLAG_CORRUPT) { NSLog(@"Skipping corrupt audio packet"); - return NO; + return nil; } // Log pts... @@ -481,16 +481,28 @@ - (BOOL) decodePacket: (AVPacket *)packet [_statusField setStringValue: _statusString]; } + NSImage *image = nil; while (avcodec_receive_frame(_videoCodecCtx, _videoFrame) == 0) { - NSImage *image = [self renderFrame: _videoFrame]; + image = [self renderFrame: _videoFrame]; + } + + return image; +} + +- (BOOL) decodePacket: (AVPacket *)packet +{ + NSImage *image = [self decodePacketToImage: packet]; + + if (image != nil) + { [self performSelectorOnMainThread: @selector(updateImage:) withObject: image waitUntilDone: NO]; AUTORELEASE(image); } - - return YES; + + return (image != nil); } - (BOOL) decodeDictionary: (NSDictionary *)dict From da4131ea93598aa006bb983fd5eaaffc9c82cf46 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Fri, 27 Jun 2025 00:59:17 -0400 Subject: [PATCH 79/86] Beginning implementation of buildCache --- Source/GSMovieView.h | 14 ++++++++++---- Source/GSMovieView.m | 31 +++++++++++++++++++++++-------- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index 13ac686db9..b590c15485 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -52,7 +52,8 @@ APPKIT_EXPORT_CLASS @interface GSMovieView : NSMovieView { - NSTimer *_feedTimer; + NSTimer *_playTimer; + NSThread *_cacheThread; NSImage *_currentFrame; NSString *_statusString; GSAudioPlayer *_audioPlayer; @@ -71,7 +72,8 @@ APPKIT_EXPORT_CLASS int64_t _savedPts; CGFloat _fps; BOOL _running; - + NSInteger _cachedCount; + // buffers NSMutableArray *_videoBuffer; NSMutableArray *_audioBuffer; @@ -84,13 +86,17 @@ APPKIT_EXPORT_CLASS // Submit packets... - (BOOL) decodePacket: (AVPacket *)packet; - (BOOL) decodeDictionary: (NSDictionary *)dict; +- (NSImage *) decodePacketToImage: (AVPacket *)packet; -// Start and stop... +// Framerate - (CGFloat) frameRateForStream; // Main loop to process packets... - (NSImage *) renderFrame: (AVFrame *)videoFrame; -- (BOOL) setup; +- (void) decodeAndDisplayNextFrame; +- (void) buildCache; + +- (BOOL) open; - (void) close; @end diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index d435564ac6..c3ecd56616 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -125,9 +125,10 @@ - (instancetype) initWithFrame: (NSRect)frame { // Objects... _audioPlayer = [[GSAudioPlayer alloc] init]; - _feedTimer = nil; + _playTimer = nil; _currentFrame = nil; - + _cacheThread = nil; + // AV... _videoClock = 0; _videoCodecCtx = NULL; @@ -136,7 +137,8 @@ - (instancetype) initWithFrame: (NSRect)frame _stream = NULL; _lastPts = 0; _fps = 0.0; - + _cachedCount = 0; + // Flags... _running = NO; // is the thread running? @@ -198,7 +200,7 @@ - (CGFloat) frameRateForStream - (void) handleNotification: (NSNotification *)notification { NSLog(@"[GSMovieView] Shutting down, final pts %ld", _lastPts); - [_feedTimer invalidate]; + [_playTimer invalidate]; } // Overridden methods from the superclass... @@ -219,7 +221,7 @@ - (IBAction) start: (id)sender [self setVolume: 1.0]; _running = YES; - _feedTimer = [NSTimer scheduledTimerWithTimeInterval: fr + _playTimer = [NSTimer scheduledTimerWithTimeInterval: fr target: self selector: @selector(decodeAndDisplayNextFrame) userInfo: nil @@ -232,7 +234,7 @@ - (IBAction) stop: (id)sender if (_running == YES) { _running = NO; - [_feedTimer invalidate]; + [_playTimer invalidate]; NSLog(@"[GSMovieView] Stopping video | Timestamp: %ld, lastPts = %ld", av_gettime(), _lastPts); } @@ -260,7 +262,7 @@ - (void) setMovie: (NSMovie *)movie @synchronized(_movie) { [super setMovie: movie]; - [self setup]; + [self open]; [self start: nil]; } } @@ -330,7 +332,7 @@ - (void) drawRect: (NSRect)dirtyRect } } -- (BOOL) setup +- (BOOL) open { NSMovie *movie = [self movie]; @@ -407,12 +409,25 @@ - (BOOL) setup avformat_close_input(&_formatCtx); return NO; } + + // Start cache thread... + _cacheThread = [[NSThread alloc] initWithTarget: self + selector: @selector(buildCache) + object: nil]; + // [_cacheThread start]; } } return YES; } +- (void) buildCache +{ + _cachedCount = 0; + // NSImage *image + // while ( +} + - (NSImage *) renderFrame: (AVFrame *)videoFrame { uint8_t *rgbData[1]; From ab3c0a7e287ad03301c5ebb0733d414dd24e5852 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 30 Jun 2025 04:52:38 -0400 Subject: [PATCH 80/86] Basic cache system implemented --- Source/GSMovieView.m | 105 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 97 insertions(+), 8 deletions(-) diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index c3ecd56616..b692e9684b 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -215,17 +215,18 @@ - (IBAction) start: (id)sender { NSTimeInterval fr = (double)(1/[self frameRateForStream]); - NSLog(@"[GSMovieView] Starting video | Timestamp: %ld, lastPts = %ld, fr = %f", - av_gettime(), _lastPts, fr); + NSLog(@"fr = %f", fr); + NSLog(@"[GSMovieView] Starting video | Timestamp: %ld, lastPts = %ld", + av_gettime(), _lastPts); [self setRate: 1.0]; [self setVolume: 1.0]; - _running = YES; _playTimer = [NSTimer scheduledTimerWithTimeInterval: fr target: self - selector: @selector(decodeAndDisplayNextFrame) + selector: @selector(displayNextFrame) userInfo: nil repeats: YES]; + } } @@ -414,18 +415,80 @@ - (BOOL) open _cacheThread = [[NSThread alloc] initWithTarget: self selector: @selector(buildCache) object: nil]; - // [_cacheThread start]; + [_cacheThread start]; } } return YES; } +- (id) decodeNext +{ + AVPacket packet; + id data = nil; + + packet.data = NULL; + packet.size = 0; + while (av_read_frame(_formatCtx, &packet) >= 0) + { + if (!_running) + { + break; + } + + if (packet.flags & AV_PKT_FLAG_CORRUPT) + { + NSLog(@"Skipping corrupt video packet"); + break; + } + + // dict = NSDictionaryFromAVPacket(&packet); + if (packet.stream_index == _videoStreamIndex) + { + data = [self decodePacketToImage: &packet]; + // NSLog(@"image = %@", data); + break; + } + else if (packet.stream_index == _audioStreamIndex) + { + data = [_audioPlayer decodePacketToData: &packet]; + // NSLog(@"sound = %@", data); + break; + } + + av_packet_unref(&packet); + } + + if (data == nil) NSLog(@"data is nil"); + return data; +} + - (void) buildCache { _cachedCount = 0; - // NSImage *image - // while ( + while (_running) // (data = [self decodeNext]) != nil) + { + id data = [self decodeNext]; + + @synchronized(_videoBuffer) + { + if (data != nil) + { + if ([data isKindOfClass: [NSImage class]]) + { + [_videoBuffer addObject: data]; + NSLog(@"Video buffer count = %ld", [_videoBuffer count]); + } + else + { + [_audioBuffer addObject: data]; + // NSLog(@"Audio buffer count = %ld", [_videoBuffer count]); + } + + _cachedCount++; + } + } + } } - (NSImage *) renderFrame: (AVFrame *)videoFrame @@ -526,6 +589,32 @@ - (BOOL) decodeDictionary: (NSDictionary *)dict return [self decodePacket: &packet]; } +- (void) displayNextFrame +{ + if (_cachedCount < 1000) + { + NSLog(@"Not yet.. %d", _cachedCount); + return; + } + + @synchronized(_videoBuffer) + { + if ([_audioBuffer count] > 0) + { + NSData *sound = [_audioBuffer objectAtIndex: 0]; + [_audioPlayer playData: sound]; + [_audioBuffer removeObjectAtIndex: 0]; + } + + if ([_videoBuffer count] > 0) + { + NSImage *image = [_videoBuffer objectAtIndex: 0]; + [self updateImage: image]; + [_videoBuffer removeObjectAtIndex: 0]; + } + } +} + - (void) decodeAndDisplayNextFrame { AVPacket packet; @@ -565,7 +654,7 @@ - (void) decodeAndDisplayNextFrame } av_packet_unref(&packet); - } + } } - (void) close From c15a39fa85fb3fa2ad6dc6b44b64e867640d5836 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 30 Jun 2025 08:50:52 -0400 Subject: [PATCH 81/86] Add ring buffer implementation --- Source/GNUmakefile | 3 +- Source/GSMovieView.m | 48 ------------------------ Source/GSRingBuffer.h | 22 +++++++++++ Source/GSRingBuffer.m | 86 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 110 insertions(+), 49 deletions(-) create mode 100644 Source/GSRingBuffer.h create mode 100644 Source/GSRingBuffer.m diff --git a/Source/GNUmakefile b/Source/GNUmakefile index b8fad0d7c8..3abcf8f098 100644 --- a/Source/GNUmakefile +++ b/Source/GNUmakefile @@ -374,7 +374,8 @@ GSCSStrength.m \ GSCSEditInfo.m \ GSCSEditVariableManager.m \ GSCSTableau.m \ -GSColorSliderCell.m +GSColorSliderCell.m \ +GSRingBuffer.m ifeq ($(BUILD_MOVIE), yes) libgnustep-gui_OBJC_FILES += GSMovieView.m diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index b692e9684b..109b28f37f 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -583,12 +583,6 @@ - (BOOL) decodePacket: (AVPacket *)packet return (image != nil); } -- (BOOL) decodeDictionary: (NSDictionary *)dict -{ - AVPacket packet = AVPacketFromNSDictionary(dict); - return [self decodePacket: &packet]; -} - - (void) displayNextFrame { if (_cachedCount < 1000) @@ -615,48 +609,6 @@ - (void) displayNextFrame } } -- (void) decodeAndDisplayNextFrame -{ - AVPacket packet; - - packet.data = NULL; - packet.size = 0; - - while (av_read_frame(_formatCtx, &packet) >= 0) - { - NSDictionary *dict = nil; - - if (!_running) - { - break; - } - - if (packet.flags & AV_PKT_FLAG_CORRUPT) - { - NSLog(@"Skipping corrupt video packet"); - break; - } - - dict = NSDictionaryFromAVPacket(&packet); - if (packet.stream_index == _videoStreamIndex) - { - [NSThread detachNewThreadSelector: @selector(decodeDictionary:) - toTarget: self - withObject: dict]; - break; - } - else if (packet.stream_index == _audioStreamIndex) - { - [NSThread detachNewThreadSelector: @selector(decodeDictionary:) - toTarget: _audioPlayer - withObject: dict]; - break; - } - - av_packet_unref(&packet); - } -} - - (void) close { if (_formatCtx != NULL) diff --git a/Source/GSRingBuffer.h b/Source/GSRingBuffer.h new file mode 100644 index 0000000000..ed5a1dd609 --- /dev/null +++ b/Source/GSRingBuffer.h @@ -0,0 +1,22 @@ +/* GSRingBuffer.m - Ring buffer implementation in Objective-C 1.0 for GNUstep */ + +#import + +@interface GSRingBuffer : NSObject +{ + id *data; + int capacity; + int head; + int tail; + int size; +} + +- (id)initWithCapacity:(int)cap; +- (void)dealloc; +- (BOOL)isEmpty; +- (BOOL)isFull; +- (BOOL)enqueue:(id)item; +- (id)dequeue; +- (id)peek; + +@end diff --git a/Source/GSRingBuffer.m b/Source/GSRingBuffer.m new file mode 100644 index 0000000000..dce6b33478 --- /dev/null +++ b/Source/GSRingBuffer.m @@ -0,0 +1,86 @@ +/* GSRingBuffer.m */ + +#import "GSRingBuffer.h" + +@implementation GSRingBuffer + +- (id)initWithCapacity: (int)cap +{ + if (cap <= 0) + return nil; + + self = [super init]; + if (self) + { + capacity = cap; + head = 0; + tail = 0; + size = 0; + + data = (id *)calloc(capacity, sizeof(id)); + if (!data) + { + [self release]; + return nil; + } + } + return self; +} + +- (void)dealloc +{ + int i; + for (i = 0; i < capacity; i++) + { + RELEASE(data[i]); + data[i] = nil; + } + free(data); + [super dealloc]; +} + +- (BOOL)isEmpty +{ + return size == 0; +} + +- (BOOL)isFull +{ + return size == capacity; +} + +- (BOOL)enqueue: (id)item +{ + if ([self isFull]) + return NO; + + data[tail] = RETAIN(item); + tail = (tail + 1) % capacity; + size++; + return YES; +} + +- (id)dequeue +{ + id item; + if ([self isEmpty]) + return nil; + + item = data[head]; + data[head] = nil; + head = (head + 1) % capacity; + size--; + return AUTORELEASE(item); +} + +- (id)peek +{ + id obj = RETAIN(data[head]); + + if ([self isEmpty]) + return nil; + + return AUTORELEASE(obj); +} + +@end From 2b4df47b441d3dd24ea77d02dc28e50223cff6d3 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 30 Jun 2025 09:57:29 -0400 Subject: [PATCH 82/86] Reduce imports in GSRingBuffer --- Source/GSRingBuffer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/GSRingBuffer.h b/Source/GSRingBuffer.h index ed5a1dd609..7545bcd344 100644 --- a/Source/GSRingBuffer.h +++ b/Source/GSRingBuffer.h @@ -1,6 +1,6 @@ /* GSRingBuffer.m - Ring buffer implementation in Objective-C 1.0 for GNUstep */ -#import +#import @interface GSRingBuffer : NSObject { From da2a7b0a7cf88fcfa3711e547fccb1c889adbc86 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 30 Jun 2025 10:06:28 -0400 Subject: [PATCH 83/86] Code cleanup --- Source/GSMovieView.h | 6 +++--- Source/GSMovieView.m | 21 +++------------------ 2 files changed, 6 insertions(+), 21 deletions(-) diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index b590c15485..9b55f7cd7c 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -84,8 +84,6 @@ APPKIT_EXPORT_CLASS streamIndex: (int)videoStreamIndex; // Submit packets... -- (BOOL) decodePacket: (AVPacket *)packet; -- (BOOL) decodeDictionary: (NSDictionary *)dict; - (NSImage *) decodePacketToImage: (AVPacket *)packet; // Framerate @@ -93,9 +91,11 @@ APPKIT_EXPORT_CLASS // Main loop to process packets... - (NSImage *) renderFrame: (AVFrame *)videoFrame; -- (void) decodeAndDisplayNextFrame; +- (id) decodeNext; - (void) buildCache; +- (void) displayNextFrame; +// Open and close movie... - (BOOL) open; - (void) close; diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 109b28f37f..24173348dd 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -459,7 +459,7 @@ - (id) decodeNext av_packet_unref(&packet); } - if (data == nil) NSLog(@"data is nil"); + // if (data == nil) NSLog(@"data is nil"); return data; } @@ -477,7 +477,7 @@ - (void) buildCache if ([data isKindOfClass: [NSImage class]]) { [_videoBuffer addObject: data]; - NSLog(@"Video buffer count = %ld", [_videoBuffer count]); + // NSLog(@"Video buffer count = %ld", [_videoBuffer count]); } else { @@ -568,26 +568,11 @@ - (NSImage *) decodePacketToImage: (AVPacket *)packet return image; } -- (BOOL) decodePacket: (AVPacket *)packet -{ - NSImage *image = [self decodePacketToImage: packet]; - - if (image != nil) - { - [self performSelectorOnMainThread: @selector(updateImage:) - withObject: image - waitUntilDone: NO]; - AUTORELEASE(image); - } - - return (image != nil); -} - - (void) displayNextFrame { if (_cachedCount < 1000) { - NSLog(@"Not yet.. %d", _cachedCount); + // NSLog(@"Not yet.. %d", _cachedCount); return; } From 56a4ebd8dcdae4e728bdec983566e6c15232de41 Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 30 Jun 2025 23:02:23 -0400 Subject: [PATCH 84/86] Add headers --- Source/GSRingBuffer.h | 39 +++++++++++++++++++++++++++++++++++++-- Source/GSRingBuffer.m | 28 ++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/Source/GSRingBuffer.h b/Source/GSRingBuffer.h index 7545bcd344..544974167f 100644 --- a/Source/GSRingBuffer.h +++ b/Source/GSRingBuffer.h @@ -1,7 +1,40 @@ +/** GSRingBuffer + + Ring buffer implementation + + Copyright (C) 2025 Free Software Foundation, Inc. + + Author: Gregory John Casamento + Date: May 2025 + + This file is part of the GNUstep GUI Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; see the file COPYING.LIB. + If not, see or write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + /* GSRingBuffer.m - Ring buffer implementation in Objective-C 1.0 for GNUstep */ +#ifndef _GNUstep_H_GSRingBuffer +#define _GNUstep_H_GSRingBuffer + #import +#import "AppKit/AppKitDefines.h" +APPKIT_EXPORT_CLASS @interface GSRingBuffer : NSObject { id *data; @@ -11,12 +44,14 @@ int size; } -- (id)initWithCapacity:(int)cap; +- (id)initWithCapacity: (int)cap; - (void)dealloc; - (BOOL)isEmpty; - (BOOL)isFull; -- (BOOL)enqueue:(id)item; +- (BOOL)enqueue: (id)item; - (id)dequeue; - (id)peek; @end + +#endif diff --git a/Source/GSRingBuffer.m b/Source/GSRingBuffer.m index dce6b33478..f077d97325 100644 --- a/Source/GSRingBuffer.m +++ b/Source/GSRingBuffer.m @@ -1,3 +1,31 @@ +/** GSRingBuffer + + Ring buffer implementation + + Copyright (C) 2025 Free Software Foundation, Inc. + + Author: Gregory John Casamento + Date: May 2025 + + This file is part of the GNUstep GUI Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; see the file COPYING.LIB. + If not, see or write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + /* GSRingBuffer.m */ #import "GSRingBuffer.h" From 13ea205636f03ae060cb7c90f694d26f6a68e4fc Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Thu, 3 Jul 2025 02:32:19 -0400 Subject: [PATCH 85/86] Ring buffer to video playback logic --- Source/GSMovieView.h | 4 ++-- Source/GSMovieView.m | 45 +++++++++++++++----------------------------- 2 files changed, 17 insertions(+), 32 deletions(-) diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index 9b55f7cd7c..57e2a52a2c 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -45,6 +45,7 @@ #include @class GSAudioPlayer; +@class GSRingBuffer; @class NSImage; @class NSMutableArray; @class NSTimer; @@ -75,8 +76,7 @@ APPKIT_EXPORT_CLASS NSInteger _cachedCount; // buffers - NSMutableArray *_videoBuffer; - NSMutableArray *_audioBuffer; + GSRingBuffer *_ringBuffer; } // Initialization... diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 24173348dd..46d87e63db 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -43,12 +43,15 @@ #import "AppKit/NSMovie.h" #import "AppKit/NSPasteboard.h" -#import "GSMovieView.h" #import "GSAudioPlayer.h" #import "GSAVUtils.h" +#import "GSMovieView.h" +#import "GSRingBuffer.h" static NSNotificationCenter *nc = nil; +#define BUFFER_SIZE 1024 + // Ignore the warning this will produce as it is intentional. #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation" @@ -143,8 +146,7 @@ - (instancetype) initWithFrame: (NSRect)frame _running = NO; // is the thread running? // buffers... - _videoBuffer = [[NSMutableArray alloc] init]; - _audioBuffer = [[NSMutableArray alloc] init]; + _ringBuffer = [[GSRingBuffer alloc] initWithCapacity: BUFFER_SIZE]; // Get notifications and shut down the thread if app is closing. [nc addObserver: self @@ -178,8 +180,7 @@ - (void)dealloc // Destroy objects DESTROY(_audioPlayer); DESTROY(_currentFrame); - DESTROY(_videoBuffer); - DESTROY(_audioBuffer); + DESTROY(_ringBuffer); // Unsubscribe to NSNotification [nc removeObserver: self]; @@ -470,19 +471,13 @@ - (void) buildCache { id data = [self decodeNext]; - @synchronized(_videoBuffer) + @synchronized(_ringBuffer) { if (data != nil) { - if ([data isKindOfClass: [NSImage class]]) - { - [_videoBuffer addObject: data]; - // NSLog(@"Video buffer count = %ld", [_videoBuffer count]); - } - else + if (![_ringBuffer isFull]) { - [_audioBuffer addObject: data]; - // NSLog(@"Audio buffer count = %ld", [_videoBuffer count]); + [_ringBuffer enqueue: data]; } _cachedCount++; @@ -570,26 +565,16 @@ - (NSImage *) decodePacketToImage: (AVPacket *)packet - (void) displayNextFrame { - if (_cachedCount < 1000) + @synchronized(_ringBuffer) { - // NSLog(@"Not yet.. %d", _cachedCount); - return; - } - - @synchronized(_videoBuffer) - { - if ([_audioBuffer count] > 0) + id data = [_ringBuffer dequeue]; + if ([data isKindOfClass: [NSData class]]) { - NSData *sound = [_audioBuffer objectAtIndex: 0]; - [_audioPlayer playData: sound]; - [_audioBuffer removeObjectAtIndex: 0]; + [_audioPlayer playData: data]; } - - if ([_videoBuffer count] > 0) + else // if ([_videoBuffer count] > 0) { - NSImage *image = [_videoBuffer objectAtIndex: 0]; - [self updateImage: image]; - [_videoBuffer removeObjectAtIndex: 0]; + [self updateImage: data]; } } } From a846b25588c75efb7f03bc43c1b997cc6831757d Mon Sep 17 00:00:00 2001 From: Gregory John Casamento Date: Mon, 21 Jul 2025 18:20:06 -0400 Subject: [PATCH 86/86] Changes to movie view to fix issues with current buffering --- Source/GSMovieView.h | 1 + Source/GSMovieView.m | 31 +++++++++++++++++++++++++------ Source/GSRingBuffer.m | 33 ++++++++++++++++++++------------- 3 files changed, 46 insertions(+), 19 deletions(-) diff --git a/Source/GSMovieView.h b/Source/GSMovieView.h index 57e2a52a2c..ce141811a1 100644 --- a/Source/GSMovieView.h +++ b/Source/GSMovieView.h @@ -55,6 +55,7 @@ APPKIT_EXPORT_CLASS { NSTimer *_playTimer; NSThread *_cacheThread; + NSThread *_runThread; NSImage *_currentFrame; NSString *_statusString; GSAudioPlayer *_audioPlayer; diff --git a/Source/GSMovieView.m b/Source/GSMovieView.m index 46d87e63db..b265892597 100644 --- a/Source/GSMovieView.m +++ b/Source/GSMovieView.m @@ -50,7 +50,7 @@ static NSNotificationCenter *nc = nil; -#define BUFFER_SIZE 1024 +#define BUFFER_SIZE 512 // Ignore the warning this will produce as it is intentional. #pragma clang diagnostic push @@ -131,6 +131,7 @@ - (instancetype) initWithFrame: (NSRect)frame _playTimer = nil; _currentFrame = nil; _cacheThread = nil; + _runThread = nil; // AV... _videoClock = 0; @@ -193,8 +194,8 @@ - (CGFloat) frameRateForStream { if (_stream->avg_frame_rate.num > 0 && _stream->avg_frame_rate.den > 0) return av_q2d(_stream->avg_frame_rate); - else - return (1.0 / av_q2d(_stream->time_base)); + + return (1.0 / av_q2d(_stream->time_base)); } // Notification responses... @@ -210,6 +211,18 @@ - (BOOL) isPlaying return _running; } +- (void) _runThread +{ + NSLog(@"Entered..."); + while (_running) + { + NSLog(@"Running..."); + [self performSelectorOnMainThread: @selector(displayNextFrame) + withObject: nil + waitUntilDone: YES]; + } +} + - (IBAction) start: (id)sender { if (_running == NO) @@ -222,12 +235,17 @@ - (IBAction) start: (id)sender [self setRate: 1.0]; [self setVolume: 1.0]; _running = YES; + _runThread = [[NSThread alloc] initWithTarget: self + selector: @selector(_runThread) + object: nil]; + [_runThread start]; + /* _playTimer = [NSTimer scheduledTimerWithTimeInterval: fr target: self selector: @selector(displayNextFrame) userInfo: nil repeats: YES]; - + */ } } @@ -236,7 +254,8 @@ - (IBAction) stop: (id)sender if (_running == YES) { _running = NO; - [_playTimer invalidate]; + // [_playTimer invalidate]; + [_runThread cancel]; NSLog(@"[GSMovieView] Stopping video | Timestamp: %ld, lastPts = %ld", av_gettime(), _lastPts); } @@ -423,7 +442,7 @@ - (BOOL) open return YES; } -- (id) decodeNext +- (AVPacket) decodeNext { AVPacket packet; id data = nil; diff --git a/Source/GSRingBuffer.m b/Source/GSRingBuffer.m index f077d97325..98c5929487 100644 --- a/Source/GSRingBuffer.m +++ b/Source/GSRingBuffer.m @@ -32,7 +32,7 @@ @implementation GSRingBuffer -- (id)initWithCapacity: (int)cap +- (id) initWithCapacity: (int)cap { if (cap <= 0) return nil; @@ -48,14 +48,14 @@ - (id)initWithCapacity: (int)cap data = (id *)calloc(capacity, sizeof(id)); if (!data) { - [self release]; + RELEASE(self); return nil; } } return self; } -- (void)dealloc +- (void) dealloc { int i; for (i = 0; i < capacity; i++) @@ -67,33 +67,38 @@ - (void)dealloc [super dealloc]; } -- (BOOL)isEmpty +- (BOOL) isEmpty { return size == 0; } -- (BOOL)isFull +- (BOOL) isFull { return size == capacity; } -- (BOOL)enqueue: (id)item +- (BOOL) enqueue: (id)item { if ([self isFull]) - return NO; - + { + return NO; + } + data[tail] = RETAIN(item); tail = (tail + 1) % capacity; size++; return YES; } -- (id)dequeue +- (id) dequeue { id item; + if ([self isEmpty]) - return nil; - + { + return nil; + } + item = data[head]; data[head] = nil; head = (head + 1) % capacity; @@ -101,12 +106,14 @@ - (id)dequeue return AUTORELEASE(item); } -- (id)peek +- (id) peek { id obj = RETAIN(data[head]); if ([self isEmpty]) - return nil; + { + return nil; + } return AUTORELEASE(obj); }