<commit_before>/*
 * consumer_sdl_still.c -- A Simple DirectMedia Layer consumer
 * Copyright (C) 2003-2004, 2010 Ushodaya Enterprises Limited
 * Author: <NAME>
 *
 * 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.1 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; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <framework/mlt_consumer.h>
#include <framework/mlt_frame.h>
#include <framework/mlt_deque.h>
#include <framework/mlt_factory.h>
#include <framework/mlt_filter.h>
#include <framework/mlt_log.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <SDL.h>
#include <SDL_syswm.h>
#include <sys/time.h>
#include "consumer_sdl_osx.h"

extern pthread_mutex_t mlt_sdl_mutex;

/** This classes definition.
*/

typedef struct consumer_sdl_s *consumer_sdl;

struct consumer_sdl_s
{
	struct mlt_consumer_s parent;
	mlt_properties properties;
	pthread_t thread;
	int joined;
	int running;
	int window_width;
	int window_height;
	int width;
	int height;
	int playing;
	int sdl_flags;
	SDL_Surface *sdl_screen;
	SDL_Rect rect;
	uint8_t *buffer;
	int last_position;
	mlt_producer last_producer;
};

/** Forward references to static functions.
*/

static int consumer_start( mlt_consumer parent );
static int consumer_stop( mlt_consumer parent );
static int consumer_is_stopped( mlt_consumer parent );
static void consumer_close( mlt_consumer parent );
static void *consumer_thread( void * );
static int consumer_get_dimensions( int *width, int *height );
static void consumer_sdl_event( mlt_listener listener, mlt_properties owner, mlt_service this, void **args );

/** This is what will be called by the factory - anything can be passed in
	via the argument, but keep it simple.
*/

mlt_consumer consumer_sdl_still_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
{
	// Create the consumer object
	consumer_sdl this = calloc( 1, sizeof( struct consumer_sdl_s ) );

	// If no malloc'd and consumer init ok
	if ( this != NULL && mlt_consumer_init( &this->parent, this, profile ) == 0 )
	{
		// Get the parent consumer object
		mlt_consumer parent = &this->parent;

		// get a handle on properties
		mlt_service service = MLT_CONSUMER_SERVICE( parent );
		this->properties = MLT_SERVICE_PROPERTIES( service );

		// We have stuff to clean up, so override the close method
		parent->close = consumer_close;

		// Default scaler (for now we'll use nearest)
		mlt_properties_set( this->properties, "rescale", "nearest" );

		// We're always going to run this in non-realtime mode
		mlt_properties_set( this->properties, "real_time", "0" );

		// Ensure we don't join on a non-running object
		this->joined = 1;
		
		// process actual param
		if ( arg == NULL || sscanf( arg, "%dx%d", &this->width, &this->height ) != 2 )
		{
			this->width = mlt_properties_get_int( this->properties, "width" );
			this->height = mlt_properties_get_int( this->properties, "height" );
		}
		else
		{
			mlt_properties_set_int( this->properties, "width", this->width );
			mlt_properties_set_int( this->properties, "height", this->height );
		}

		// Set the sdl flags
		this->sdl_flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL | SDL_RESIZABLE | SDL_DOUBLEBUF;

		// Allow thread to be started/stopped
		parent->start = consumer_start;
		parent->stop = consumer_stop;
		parent->is_stopped = consumer_is_stopped;

		// Register specific events
		mlt_events_register( this->properties, "consumer-sdl-event", ( mlt_transmitter )consumer_sdl_event );

		// Return the consumer produced
		return parent;
	}

	// malloc or consumer init failed
	free( this );

	// Indicate failure
	return NULL;
}

static void consumer_sdl_event( mlt_listener listener, mlt_properties owner, mlt_service this, void **args )
{
	if ( listener != NULL )
		listener( owner, this, ( SDL_Event * )args[ 0 ] );
}

static int consumer_start( mlt_consumer parent )
{
	consumer_sdl this = parent->child;

	if ( !this->running )
	{
		int preview_off = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( parent ), "preview_off" );
		int sdl_started = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( parent ), "sdl_started" );

		consumer_stop( parent );

		this->last_position = -1;
		this->running = 1;
		this->joined = 0;

		// Allow the user to force resizing to window size
		this->width = mlt_properties_get_int( this->properties, "width" );
		this->height = mlt_properties_get_int( this->properties, "height" );

		// Default window size
		double display_ratio = mlt_properties_get_double( this->properties, "display_ratio" );
		this->window_width = ( double )this->height * display_ratio + 0.5;
		this->window_height = this->height;

		if ( sdl_started == 0 && preview_off == 0 )
		{
			pthread_mutex_lock( &mlt_sdl_mutex );
			int ret = SDL_Init( SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE );
			pthread_mutex_unlock( &mlt_sdl_mutex );
			if ( ret < 0 )
			{
				fprintf( stderr, "Failed to initialize SDL: %s\n", SDL_GetError() );
				return -1;
			}

			SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL );
			SDL_EnableUNICODE( 1 );
		}
		else if ( preview_off == 0 )
		{
			pthread_mutex_lock( &mlt_sdl_mutex );
			SDL_Surface *screen = SDL_GetVideoSurface( );
			pthread_mutex_unlock( &mlt_sdl_mutex );
			if ( screen != NULL )
			{
				this->sdl_screen = screen;
			}
		}

		if ( this->sdl_screen == NULL && preview_off == 0 )
		{
			pthread_mutex_lock( &mlt_sdl_mutex );
			this->sdl_screen = SDL_SetVideoMode( this->window_width, this->window_height, 0, this->sdl_flags );
			pthread_mutex_unlock( &mlt_sdl_mutex );
		}

		pthread_create( &this->thread, NULL, consumer_thread, this );
	}

	return 0;
}

static int consumer_stop( mlt_consumer parent )
{
	// Get the actual object
	consumer_sdl this = parent->child;

	if ( this->joined == 0 )
	{
		int preview_off = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( parent ), "preview_off" );
		int sdl_started = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( parent ), "sdl_started" );
	
		// Kill the thread and clean up
		this->running = 0;

		pthread_join( this->thread, NULL );
		this->joined = 1;

		if ( sdl_started == 0 && preview_off == 0 )
		{
			pthread_mutex_lock( &mlt_sdl_mutex );
			SDL_Quit( );
			pthread_mutex_unlock( &mlt_sdl_mutex );
		}

		this->sdl_screen = NULL;
	}

	return 0;
}

static int consumer_is_stopped( mlt_consumer parent )
{
	consumer_sdl this = parent->child;
	return !this->running;
}

static int sdl_lock_display( )
{
	pthread_mutex_lock( &mlt_sdl_mutex );
	SDL_Surface *screen = SDL_GetVideoSurface( );
	int result = screen != NULL && ( !SDL_MUSTLOCK( screen ) || SDL_LockSurface( screen ) >= 0 );
	pthread_mutex_unlock( &mlt_sdl_mutex );
	return result;
}

static void sdl_unlock_display( )
{
	pthread_mutex_lock( &mlt_sdl_mutex );
	SDL_Surface *screen = SDL_GetVideoSurface( );
	if ( screen != NULL && SDL_MUSTLOCK( screen ) )
		SDL_UnlockSurface( screen );
	pthread_mutex_unlock( &mlt_sdl_mutex );<commit_msg>sdl/consumer_sdl_still.c: use mutex when changing sdl_screen<commit_after>/*
 * consumer_sdl_still.c -- A Simple DirectMedia Layer consumer
 * Copyright (C) 2003-2004, 2010 Ushodaya Enterprises Limited
 * Author: Charles Yates
 *
 * 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.1 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; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <framework/mlt_consumer.h>
#include <framework/mlt_frame.h>
#include <framework/mlt_deque.h>
#include <framework/mlt_factory.h>
#include <framework/mlt_filter.h>
#include <framework/mlt_log.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <SDL.h>
#include <SDL_syswm.h>
#include <sys/time.h>
#include "consumer_sdl_osx.h"

extern pthread_mutex_t mlt_sdl_mutex;

/** This classes definition.
*/

typedef struct consumer_sdl_s *consumer_sdl;

struct consumer_sdl_s
{
	struct mlt_consumer_s parent;
	mlt_properties properties;
	pthread_t thread;
	int joined;
	int running;
	int window_width;
	int window_height;
	int width;
	int height;
	int playing;
	int sdl_flags;
	SDL_Surface *sdl_screen;
	SDL_Rect rect;
	uint8_t *buffer;
	int last_position;
	mlt_producer last_producer;
};

/** Forward references to static functions.
*/

static int consumer_start( mlt_consumer parent );
static int consumer_stop( mlt_consumer parent );
static int consumer_is_stopped( mlt_consumer parent );
static void consumer_close( mlt_consumer parent );
static void *consumer_thread( void * );
static int consumer_get_dimensions( int *width, int *height );
static void consumer_sdl_event( mlt_listener listener, mlt_properties owner, mlt_service this, void **args );

/** This is what will be called by the factory - anything can be passed in
	via the argument, but keep it simple.
*/

mlt_consumer consumer_sdl_still_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
{
	// Create the consumer object
	consumer_sdl this = calloc( 1, sizeof( struct consumer_sdl_s ) );

	// If no malloc'd and consumer init ok
	if ( this != NULL && mlt_consumer_init( &this->parent, this, profile ) == 0 )
	{
		// Get the parent consumer object
		mlt_consumer parent = &this->parent;

		// get a handle on properties
		mlt_service service = MLT_CONSUMER_SERVICE( parent );
		this->properties = MLT_SERVICE_PROPERTIES( service );

		// We have stuff to clean up, so override the close method
		parent->close = consumer_close;

		// Default scaler (for now we'll use nearest)
		mlt_properties_set( this->properties, "rescale", "nearest" );

		// We're always going to run this in non-realtime mode
		mlt_properties_set( this->properties, "real_time", "0" );

		// Ensure we don't join on a non-running object
		this->joined = 1;
		
		// process actual param
		if ( arg == NULL || sscanf( arg, "%dx%d", &this->width, &this->height ) != 2 )
		{
			this->width = mlt_properties_get_int( this->properties, "width" );
			this->height = mlt_properties_get_int( this->properties, "height" );
		}
		else
		{
			mlt_properties_set_int( this->properties, "width", this->width );
			mlt_properties_set_int( this->properties, "height", this->height );
		}

		// Set the sdl flags
		this->sdl_flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL | SDL_RESIZABLE | SDL_DOUBLEBUF;

		// Allow thread to be started/stopped
		parent->start = consumer_start;
		parent->stop = consumer_stop;
		parent->is_stopped = consumer_is_stopped;

		// Register specific events
		mlt_events_register( this->properties, "consumer-sdl-event", ( mlt_transmitter )consumer_sdl_event );

		// Return the consumer produced
		return parent;
	}

	// malloc or consumer init failed
	free( this );

	// Indicate failure
	return NULL;
}

static void consumer_sdl_event( mlt_listener listener, mlt_properties owner, mlt_service this, void **args )
{
	if ( listener != NULL )
		listener( owner, this, ( SDL_Event * )args[ 0 ] );
}

static int consumer_start( mlt_consumer parent )
{
	consumer_sdl this = parent->child;

	if ( !this->running )
	{
		int preview_off = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( parent ), "preview_off" );
		int sdl_started = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( parent ), "sdl_started" );

		consumer_stop( parent );

		this->last_position = -1;
		this->running = 1;
		this->joined = 0;

		// Allow the user to force resizing to window size
		this->width = mlt_properties_get_int( this->properties, "width" );
		this->height = mlt_properties_get_int( this->properties, "height" );

		// Default window size
		double display_ratio = mlt_properties_get_double( this->properties, "display_ratio" );
		this->window_width = ( double )this->height * display_ratio + 0.5;
		this->window_height = this->height;

		if ( sdl_started == 0 && preview_off == 0 )
		{
			pthread_mutex_lock( &mlt_sdl_mutex );
			int ret = SDL_Init( SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE );
			pthread_mutex_unlock( &mlt_sdl_mutex );
			if ( ret < 0 )
			{
				fprintf( stderr, "Failed to initialize SDL: %s\n", SDL_GetError() );
				return -1;
			}

			SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL );
			SDL_EnableUNICODE( 1 );
		}
		else if ( preview_off == 0 )
		{
			pthread_mutex_lock( &mlt_sdl_mutex );
			SDL_Surface *screen = SDL_GetVideoSurface( );
			pthread_mutex_unlock( &mlt_sdl_mutex );
			if ( screen != NULL )
			{
				this->sdl_screen = screen;
			}
		}

		if ( this->sdl_screen == NULL && preview_off == 0 )
		{
			pthread_mutex_lock( &mlt_sdl_mutex );
			this->sdl_screen = SDL_SetVideoMode( this->window_width, this->window_height, 0, this->sdl_flags );
			pthread_mutex_unlock( &mlt_sdl_mutex );
		}

		pthread_create( &this->thread, NULL, consumer_thread, this );
	}

	return 0;
}

static int consumer_stop( mlt_consumer parent )
{
	// Get the actual object
	consumer_sdl this = parent->child;

	if ( this->joined == 0 )
	{
		int preview_off = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( parent ), "preview_off" );
		int sdl_started = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( parent ), "sdl_started" );
	
		// Kill the thread and clean up
		this->running = 0;

		pthread_join( this->thread, NULL );
		this->joined = 1;

		if ( sdl_started == 0 && preview_off == 0 )
		{
			pthread_mutex_lock( &mlt_sdl_mutex );
			SDL_Quit( );
			pthread_mutex_unlock( &mlt_sdl_mutex );
		}

		pthread_mutex_lock( &mlt_sdl_mutex );
		this->sdl_screen = NULL;
		pthread_mutex_unlock( &mlt_sdl_mutex );
	}

	return 0;
}

static int consumer_is_stopped( mlt_consumer parent )
{
	consumer_sdl this = parent->child;
	return !this->running;
}

static int sdl_lock_display( )
{
	pthread_mutex_lock( &mlt_sdl_mutex );
	SDL_Surface *screen = SDL_GetVideoSurface( );
	int result = screen != NULL && ( !SDL_MUSTLOCK( screen ) || SDL_LockSurface( screen ) >= 0 );
	pthread_mutex_unlock( &mlt_sdl_mutex );
	return result;
}

static void sdl_unlock_display( )
{
	pthread_mutex_lock( &mlt_sdl_mutex );
	SDL_Surface *screen = SDL_GetVideoSurface( );
	if ( screen != NULL && SDL_MUSTLOCK( screen ) )
		SDL_UnlockSurface( screen );
	pthread_mutex_unlock( &mlt_sdl_mutex );
{'fraction_non_alphanumeric': 0.10815602836879433, 'fraction_numerical': 0.007354872603099553, 'mean_word_length': 4.2860118014578275, 'pattern_counts': {'":': 0, '<': 32, '<?xml version=': 0, '>': 134, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6328084', 'n_tokens_mistral': 5715, 'n_tokens_neox': 5082, 'n_words': 1422}