Changes to use ffplay

This commit is contained in:
Gregory John Casamento 2022-04-10 12:33:06 -04:00
parent f01fe1f152
commit 0b7e229c39
9 changed files with 112 additions and 262 deletions

View file

@ -38,21 +38,14 @@
@protocol GSVideoSink <NSObject>
+ (BOOL) canInitWithData: (NSData *)d;
/**
* Opens the device for output, called by [NSMovie-play].
*/
- (BOOL) open;
/** Closes the device, called by [NSMovie-stop].
*/
- (void) close;
+ (BOOL) canInitWithData: (NSData *)data;
/**
* Plays the data in bytes
*/
- (BOOL) playBytes: (void *)bytes length: (NSUInteger)length;
- (void) play;
- (void) stop;
/** Called by [NSMovieView -setVolume:], and corresponds to it. Parameter volume
* is between the values 0.0 and 1.0.

View file

@ -54,11 +54,6 @@
*/
- (id)initWithData: (NSData *)data;
/** Reads data provided in -initWithData:. Parameter bytes must be big enough
* to hold length bytes.
*/
- (NSUInteger)readBytes: (void *)bytes length: (NSUInteger)length;
/** Returns the duration, in seconds. Equivalent to [NSMovieView-duration].
*/
- (NSTimeInterval)duration;

View file

@ -657,6 +657,8 @@ GSImageMagickImageRep.h \
GSInstantiator.h \
GSSoundSink.h \
GSSoundSource.h \
GSVideoSink.h \
GSVideoSource.h \
GSWindowDecorationView.h \
GSXibElement.h \
GSXibLoading.h \

View file

@ -62,6 +62,8 @@ static inline void _loadNSMoviePlugIns (void)
NSBundle *bundle = [NSBundle bundleWithPath: path];
paths = [bundle pathsForResourcesOfType: @"nsmovie"
inDirectory: @"Bundles"];
NSLog(@"NSMovie paths = %@", paths);
[all addObjectsFromArray: paths];
}
END_FOR_IN(paths);
@ -69,6 +71,7 @@ static inline void _loadNSMoviePlugIns (void)
// Check all paths for bundles conforming to the protocol...
FOR_IN(NSString*, path, all)
{
NSLog(@"path = %@", path);
NSBundle *bundle = [NSBundle bundleWithPath: path];
Class plugInClass = [bundle principalClass];
if ([plugInClass conformsToProtocol: @protocol(GSVideoSource)])
@ -140,7 +143,7 @@ static inline void _loadNSMoviePlugIns (void)
// Choose video sink...
FOR_IN(Class, pluginClass, __videoSinkPlugIns)
{
if ([pluginClass canInitWithData: movieData])
// if ([pluginClass canInitWithData: movieData])
{
_sink = [[pluginClass alloc] init];
}
@ -150,7 +153,7 @@ static inline void _loadNSMoviePlugIns (void)
// Choose video source...
FOR_IN(Class, pluginClass, __videoSourcePlugIns)
{
if ([pluginClass canInitWithData: movieData])
// if ([pluginClass canInitWithData: movieData])
{
_source = [[pluginClass alloc] initWithData: movieData];
}
@ -181,11 +184,11 @@ static inline void _loadNSMoviePlugIns (void)
NSData* data = [url resourceDataUsingCache: YES];
self = [self initWithData: data];
if (byRef)
if (self != nil)
{
ASSIGN(_url, url);
}
return self;
}
@ -237,7 +240,7 @@ static inline void _loadNSMoviePlugIns (void)
return _url;
}
// NSCopying protocoll
// NSCopying protocol
- (id) copyWithZone: (NSZone *)zone
{
NSMovie *new = (NSMovie*)NSCopyObject (self, 0, zone);
@ -249,7 +252,7 @@ static inline void _loadNSMoviePlugIns (void)
return new;
}
// NSCoding protocoll
// NSCoding protocol
- (void) encodeWithCoder: (NSCoder*)aCoder
{
if ([aCoder allowsKeyedCoding])
@ -277,4 +280,10 @@ static inline void _loadNSMoviePlugIns (void)
return self;
}
// Private methods...
- (NSData *) movieData
{
return _movieData;
}
@end

View file

@ -65,6 +65,7 @@ enum
- (void) _finished: (NSNumber *)finishedPlaying;
@end
/*
@implementation NSMovieView (PrivateMethods)
- (void) _stream
{
@ -118,6 +119,7 @@ enum
DESTROY(_playbackLock);
}
@end
*/
@implementation NSMovieView
@ -179,6 +181,8 @@ enum
withObject: nil];
[_readLock unlockWithCondition: MOVIE_SHOULD_PLAY];
*/
[[_movie _sink] play];
}
- (void) stop: (id)sender
@ -196,7 +200,6 @@ enum
// Set to MOVIE_SHOULD_PLAY so that thread isn't blocked.
[_readLock unlockWithCondition: MOVIE_SHOULD_PLAY];
*/
}
- (BOOL) isPlaying

View file

@ -26,6 +26,6 @@ VideoFile_PRINCIPAL_CLASS = VideoFileSource
VideoOutput_PRINCIPAL_CLASS = VidioOutputSink
VideoFile_BUNDLE_LIBS =
VideoOutput_BUNDLE_LIBS = -lavformat -lavcodec -lSDL2
VideoOutput_BUNDLE_LIBS = -lavformat -lavcodec -lavdevice -lswscale -lswresample -lSDL2
include $(GNUSTEP_MAKEFILES)/bundle.make

View file

@ -1,7 +1,7 @@
/*
VideofileSource.m
Load and read video data using libvideofile.
Load and read video data
Copyright (C) 2009 Free Software Foundation, Inc.
@ -57,11 +57,13 @@
@"mov", @"mp4", @"3gp", @"mpegts", @"mpjpeg", @"rawvideo", @"sbg",
@"tedcaptions", @"vapoursynth",nil];
}
+ (NSArray *)videoUnfilteredTypes
{
/* FIXME: I'm not sure what the UTI for all the types above are. */
return [self videoUnfilteredFileTypes];
}
+ (BOOL)canInitWithData: (NSData *)data
{
return YES;
@ -87,28 +89,6 @@
return self;
}
- (NSUInteger) readBytes: (void *)bytes length: (NSUInteger)length
{
NSRange range;
NSUInteger len = length; //- 1;
if (_currentPosition >= [_data length] - 1)
{
return 0;
}
if (length > [_data length] - _currentPosition)
{
len = [_data length] - _currentPosition;
}
range = NSMakeRange(_currentPosition, len);
[_data getBytes: bytes range: range];
_currentPosition += len;
return len;
}
- (NSTimeInterval)duration
{
return _dur;

View file

@ -61,115 +61,44 @@
#define INBUF_SIZE 4096
int video_main(NSMovie *movie, NSMovieView *view);
int video_main(NSMovieView *view);
@interface VideoOutputSink : NSObject <GSVideoSink>
{
AVCodec *_codec;
AVCodecParserContext *_parser;
AVCodecContext *_context; // = NULL;
AVPacket *_pkt;
AVFrame *_frame;
NSMovieView *_movieView;
}
@end
@implementation VideoOutputSink
+ (BOOL) canInitWithData: (NSData *)data
{
return YES; // for now just say yes...
}
- (void) display: (unsigned char *) buf
wrap: (int) wrap
xsize: (int) xsize
ysize: (int) ysize
{
/*
FILE *f;
int i;
f = fopen(filename,"wb");
fprintf(f, "P5\n%d %d\n%d\n", xsize, ysize, 255);
for (i = 0; i < ysize; i++)
fwrite(buf + i * wrap, 1, xsize, f);
fclose(f);
*/
NSLog(@"Playing...");
}
- (void) decode
{
int ret;
ret = avcodec_send_packet(_context, _pkt);
if (ret < 0)
{
NSLog(@"Error sending a packet for decoding\n");
return;
}
while (ret >= 0)
{
ret = avcodec_receive_frame(_context, _frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
{
return;
}
else if (ret < 0)
{
NSLog(@"Error during decoding\n");
return;
}
NSLog(@"saving frame %3d\n", _context->frame_number);
fflush(stdout);
/* the picture is allocated by the decoder. no need to
free it */
// snprintf(buf, sizeof(buf), "%d", _context->frame_number);
[self display: _frame->data[0]
wrap: _frame->linesize[0]
xsize: _frame->width
ysize: _frame->height];
// pgm_save(frame->data[0], frame->linesize[0],
// frame->width, frame->height, buf);
}
}
- (void)dealloc
{
[self close];
_movieView = nil;
_pkt = NULL;
_context = NULL;
_parser = NULL;
_frame = NULL;
[super dealloc];
}
- (id)init
- (id)initWithMovieView: (NSMovieView *)movieView
{
self = [super init];
if (self != nil)
{
_movieView = nil;
_pkt = NULL;
_context = NULL;
_parser = NULL;
_frame = NULL;
[self setMovieView: movieView]; // weak
}
return self;
}
- (void)setVolume: (float)volume
{
}
- (CGFloat)volume
{
return 1.0;
}
- (void) setMovieView: (NSMovieView *)view
{
_movieView = view; // weak, don't retain since the view is retained by its parent view.
@ -180,119 +109,13 @@ int video_main(NSMovie *movie, NSMovieView *view);
return _movieView;
}
- (BOOL)open
- (void) stop
{
_pkt = av_packet_alloc();
if (!_pkt)
{
NSLog(@"Could not allocate packet");
return NO;
}
_codec = avcodec_find_decoder(AV_CODEC_ID_MPEG4); // will set this based on file type.
if (!_codec)
{
NSLog(@"Could not find decoder for type");
return NO;
}
_parser = av_parser_init(_codec->id);
if (!_parser)
{
NSLog(@"Could not init parser");
return NO;
}
_context = avcodec_alloc_context3(_codec);
if (!_context)
{
NSLog(@"Could not allocate video coder context");
return NO;
}
/* open it */
if (avcodec_open2(_context, _codec, NULL) < 0)
{
NSLog(@"Could not open codec\n");
return NO;
}
_frame = av_frame_alloc();
if (!_frame)
{
NSLog(@"Could not allocate video frame\n");
return NO;
}
return YES;
}
- (void)close
{
if (_parser != NULL)
{
av_parser_close(_parser);
}
if (_context != NULL)
{
avcodec_free_context(&_context);
}
if (_frame != NULL)
{
av_frame_free(&_frame);
}
if (_pkt != NULL)
{
av_packet_free(&_pkt);
}
}
- (void) play
{
}
- (BOOL)playBytes: (void *)bytes length: (NSUInteger)length
{
int ret = av_parser_parse2(_parser, _context, &_pkt->data, &_pkt->size,
bytes, length, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
if (ret < 0)
{
NSLog(@"Error encountered while parsing data");
return NO;
}
if (_pkt != NULL)
{
if (_pkt->size)
{
[self decode];
}
else
{
NSLog(@"Packet size is 0");
}
}
else
{
NSLog(@"Invalid packet, can't play data");
return NO;
}
return YES;
}
- (void)setVolume: (float)volume
{
}
- (CGFloat)volume
{
return 1.0;
video_main(_movieView);
}
@end

View file

@ -66,6 +66,12 @@
#import <AppKit/NSMovieView.h>
#import <AppKit/NSMovie.h>
@interface NSMovie (__ffplay_PrivateMethod_)
- (NSData *) movieData;
@end
const char program_name[] = "ffplay";
const int program_birth_year = 2003;
@ -363,7 +369,7 @@ static int nb_vfilters = 0;
static char *afilters = NULL;
#endif
static int autorotate = 1;
static int find_stream_info = 1;
// static int find_stream_info = 1;
static int filter_nbthreads = 0;
/* current context */
@ -1875,7 +1881,7 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c
AVFilterContext *filt_src = NULL, *filt_out = NULL, *last_filter = NULL;
AVCodecParameters *codecpar = is->video_st->codecpar;
AVRational fr = av_guess_frame_rate(is->ic, is->video_st, NULL);
AVDictionaryEntry *e = NULL;
// AVDictionaryEntry *e = NULL;
int nb_pix_fmts = 0;
int i, j;
@ -1889,12 +1895,14 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c
}
pix_fmts[nb_pix_fmts] = AV_PIX_FMT_NONE;
/*
while ((e = av_dict_get(sws_dict, "", e, AV_DICT_IGNORE_SUFFIX))) {
if (!strcmp(e->key, "sws_flags")) {
av_strlcatf(sws_flags_str, sizeof(sws_flags_str), "%s=%s:", "flags", e->value);
} else
av_strlcatf(sws_flags_str, sizeof(sws_flags_str), "%s=%s:", e->key, e->value);
}
*/
if (strlen(sws_flags_str))
sws_flags_str[strlen(sws_flags_str)-1] = '\0';
@ -1978,7 +1986,7 @@ static int configure_audio_filters(VideoState *is, const char *afilters, int for
int channels[2] = { 0, -1 };
AVFilterContext *filt_asrc = NULL, *filt_asink = NULL;
char aresample_swr_opts[512] = "";
AVDictionaryEntry *e = NULL;
// AVDictionaryEntry *e = NULL;
char asrc_args[256];
int ret;
@ -1986,9 +1994,10 @@ static int configure_audio_filters(VideoState *is, const char *afilters, int for
if (!(is->agraph = avfilter_graph_alloc()))
return AVERROR(ENOMEM);
is->agraph->nb_threads = filter_nbthreads;
/*
while ((e = av_dict_get(swr_opts, "", e, AV_DICT_IGNORE_SUFFIX)))
av_strlcatf(aresample_swr_opts, sizeof(aresample_swr_opts), "%s=%s:", e->key, e->value);
*/
if (strlen(aresample_swr_opts))
aresample_swr_opts[strlen(aresample_swr_opts)-1] = '\0';
av_opt_set(is->agraph, "aresample_swr_opts", aresample_swr_opts, 0);
@ -2641,7 +2650,7 @@ static int stream_component_open(VideoState *is, int stream_index)
if (fast)
avctx->flags2 |= AV_CODEC_FLAG2_FAST;
opts = filter_codec_opts(codec_opts, avctx->codec_id, ic, ic->streams[stream_index], codec);
// opts = filter_codec_opts(codec_opts, avctx->codec_id, ic, ic->streams[stream_index], codec);
if (!av_dict_get(opts, "threads", NULL, 0))
av_dict_set(&opts, "threads", "auto", 0);
if (stream_lowres)
@ -2773,14 +2782,14 @@ static int read_thread(void *arg)
{
VideoState *is = arg;
AVFormatContext *ic = NULL;
int err, i, ret;
int /* err, */ i, ret;
int st_index[AVMEDIA_TYPE_NB];
AVPacket pkt1, *pkt = &pkt1;
int64_t stream_start_time;
int pkt_in_play_range = 0;
AVDictionaryEntry *t;
SDL_mutex *wait_mutex = SDL_CreateMutex();
int scan_all_pmts_set = 0;
// int scan_all_pmts_set = 0;
int64_t pkt_ts;
if (!wait_mutex) {
@ -2800,6 +2809,7 @@ static int read_thread(void *arg)
}
ic->interrupt_callback.callback = decode_interrupt_cb;
ic->interrupt_callback.opaque = is;
/*
if (!av_dict_get(format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) {
av_dict_set(&format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE);
scan_all_pmts_set = 1;
@ -2818,6 +2828,7 @@ static int read_thread(void *arg)
ret = AVERROR_OPTION_NOT_FOUND;
goto fail;
}
*/
is->ic = ic;
if (genpts)
@ -2825,6 +2836,7 @@ static int read_thread(void *arg)
av_format_inject_global_side_data(ic);
/*
if (find_stream_info) {
AVDictionary **opts = setup_find_stream_info_opts(ic, codec_opts);
int orig_nb_streams = ic->nb_streams;
@ -2842,13 +2854,18 @@ static int read_thread(void *arg)
goto fail;
}
}
*/
if (ic->pb)
ic->pb->eof_reached = 0; // FIXME hack, ffplay maybe should not use avio_feof() to test for the end
if (seek_by_bytes < 0)
seek_by_bytes = !!(ic->iformat->flags & AVFMT_TS_DISCONT) && strcmp("ogg", ic->iformat->name);
{
int c = strcmp("ogg", ic->iformat->name);
int f = ic->iformat->flags;
seek_by_bytes = !!(f & AVFMT_TS_DISCONT) && c;
}
is->max_frame_duration = (ic->iformat->flags & AVFMT_TS_DISCONT) ? 10.0 : 3600.0;
if (!window_title && (t = av_dict_get(ic->metadata, "title", NULL, 0)))
@ -3091,6 +3108,12 @@ static int read_thread(void *arg)
static VideoState *stream_open(const char *filename, AVInputFormat *iformat)
{
VideoState *is;
AVInputFormat *ifmt;
ifmt = av_mallocz(sizeof(AVInputFormat));
if (!ifmt)
return NULL;
memcpy(ifmt, iformat, sizeof(AVInputFormat));
is = av_mallocz(sizeof(VideoState));
if (!is)
@ -3101,7 +3124,7 @@ static VideoState *stream_open(const char *filename, AVInputFormat *iformat)
is->filename = av_strdup(filename);
if (!is->filename)
goto fail;
is->iformat = iformat;
is->iformat = ifmt;
is->ytop = 0;
is->xleft = 0;
@ -3695,13 +3718,16 @@ void show_help_default(const char *opt, const char *arg)
*/
/* Called from the main */
int video_main(NSMovie *movie, NSMovieView *view) //(int argc, char **argv)
int video_main(NSMovieView *view) //(int argc, char **argv)
{
int flags;
int flags = 0;
VideoState *is;
init_dynload();
NSMovie *movie = [view movie];
// init_dynload();
// initialize...
file_iformat = NULL;
av_log_set_flags(AV_LOG_SKIP_REPEATED);
// parse_loglevel(argc, argv, options);
@ -3711,7 +3737,7 @@ int video_main(NSMovie *movie, NSMovieView *view) //(int argc, char **argv)
#endif
avformat_network_init();
init_opts();
// init_opts();
signal(SIGINT , sigterm_handler); /* Interrupt (ANSI). */
signal(SIGTERM, sigterm_handler); /* Termination (ANSI). */
@ -3719,14 +3745,33 @@ int video_main(NSMovie *movie, NSMovieView *view) //(int argc, char **argv)
// show_banner(argc, argv, options);
// parse_options(NULL, argc, argv, options, opt_input_file);
input_filename = [[[movie URL] path] cString];
if (!input_filename) {
// show_usage();
av_log(NULL, AV_LOG_FATAL, "An input file must be specified\n");
av_log(NULL, AV_LOG_FATAL,
"Use -h to get full help or, even better, run 'man %s'\n", program_name);
exit(1);
NSString *path = [[movie URL] path];
input_filename = [path cString];
if (!input_filename)
{
NSString *tmp = NSTemporaryDirectory();
NSUUID *uuid = [NSUUID UUID];
NSString *tempFile = [tmp stringByAppendingPathComponent: [uuid UUIDString]];
NSData *data = [movie movieData];
if (data != nil)
{
[data writeToFile: tempFile atomically: YES];
input_filename = [tempFile cString];
}
}
// Instantiate iformat...
const char *fmt = [[path pathExtension] cString];
NSLog(@"fmt = %s", fmt);
file_iformat = av_find_input_format(fmt);
if (!file_iformat) {
av_log(NULL, AV_LOG_FATAL, "Unknown input format: %s\n", fmt);
return AVERROR(EINVAL);
}
// Set the format name...
file_iformat->name = [[path pathExtension] cString];
file_iformat->flags = flags;
if (display_disable) {
video_disable = 1;