ratio to square pixels.
int progressive - indicates whether to use progressive or field-
based rendering, default 0 (off).
+ int audio_buffer - size of the sdl audio buffer (default: 1024)
Read Only Properties
// Aspect ratio and other jiggery pokery
mlt_properties_set_double( frame_properties, "consumer_aspect_ratio", mlt_properties_get_double( properties, "aspect_ratio" ) );
- mlt_properties_set_int( frame_properties, "consumer_progressive", mlt_properties_get_int( properties, "progressive" ) );
- mlt_properties_set_int( frame_properties, "consumer_deinterlace", mlt_properties_get_int( properties, "deinterlace" ) );
+ if ( mlt_properties_get_int( properties, "progressive" ) || mlt_properties_get_int( properties, "deinterlace" ) )
+ mlt_properties_set_int( properties, "consumer_deinterlace", 1 );
}
// Return the frame
uint8_t *mlt_frame_get_alpha_mask( mlt_frame this )
{
- if ( this->get_alpha_mask != NULL )
+ if ( this != NULL && this->get_alpha_mask != NULL )
return this->get_alpha_mask( this );
- return NULL;
+ return this == NULL ? NULL : mlt_properties_get_data( &this->parent, "alpha", NULL );
}
int mlt_frame_get_audio( mlt_frame this, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples )
return ret;
}
+uint8_t *mlt_resize_alpha( uint8_t *input, int owidth, int oheight, int iwidth, int iheight )
+{
+ uint8_t *output = NULL;
+
+ if ( input != NULL && ( iwidth != owidth || iheight != oheight ) )
+ {
+ iwidth = iwidth - ( iwidth % 2 );
+ owidth = owidth - ( owidth % 2 );
+
+ output = mlt_pool_alloc( owidth * oheight );
+
+ // Coordinates (0,0 is middle of output)
+ int y;
+
+ // Calculate ranges
+ int out_x_range = owidth / 2;
+ int out_y_range = oheight / 2;
+ int in_x_range = iwidth / 2 < out_x_range ? iwidth / 2 : out_x_range;
+ int in_y_range = iheight / 2 < out_y_range ? iheight / 2 : out_y_range;
+
+ // Output pointers
+ uint8_t *out_line = output;
+ uint8_t *out_ptr = out_line;
+
+ // Calculate a middle and possibly invalid pointer in the input
+ uint8_t *in_middle = input + iwidth * ( iheight / 2 ) + ( iwidth / 2 );
+ int in_line = - in_y_range * iwidth - in_x_range;
+
+ int elements;
+
+ // Fill whole section with black
+ y = out_y_range - ( iheight / 2 );
+ int blank_elements = owidth * y;
+ elements = blank_elements;
+ while ( elements -- )
+ *out_line ++ = 0;
+
+ int active_width = iwidth;
+ int inactive_width = out_x_range - in_x_range;
+ uint8_t *p = NULL;
+ uint8_t *end = NULL;
+
+ // Loop for the entirety of our output height.
+ while ( iheight -- )
+ {
+ // Start at the beginning of the line
+ out_ptr = out_line;
+
+ // Fill the outer part with black
+ elements = inactive_width;
+ while ( elements -- )
+ *out_ptr ++ = 0;
+
+ // We're in the input range for this row.
+ p = in_middle + in_line;
+ end = out_ptr + active_width;
+ while ( out_ptr != end )
+ *out_ptr ++ = *p ++;
+
+ // Fill the outer part with black
+ elements = inactive_width;
+ while ( elements -- )
+ *out_ptr ++ = 0;
+
+ // Move to next input line
+ in_line += iwidth;
+
+ // Move to next output line
+ out_line += owidth;
+ }
+
+ // Fill whole section with black
+ elements = blank_elements;
+ while ( elements -- )
+ *out_line ++ = 0;
+ }
+
+ return output;
+}
+
void mlt_resize_yuv422( uint8_t *output, int owidth, int oheight, uint8_t *input, int iwidth, int iheight )
{
// Calculate strides
iwidth = iwidth - ( iwidth % 4 );
owidth = owidth - ( owidth % 4 );
- iheight = iheight - ( iheight % 2 );
- oheight = oheight - ( oheight % 2 );
+ //iheight = iheight - ( iheight % 2 );
+ //oheight = oheight - ( oheight % 2 );
// Optimisation point
if ( iwidth == owidth && iheight == oheight )
// Get the input image, width and height
uint8_t *input = mlt_properties_get_data( properties, "image", NULL );
+ uint8_t *alpha = mlt_frame_get_alpha_mask( this );
+
int iwidth = mlt_properties_get_int( properties, "width" );
int iheight = mlt_properties_get_int( properties, "height" );
mlt_properties_set_int( properties, "width", owidth );
mlt_properties_set_int( properties, "height", oheight );
+ // We should resize the alpha too
+ alpha = mlt_resize_alpha( alpha, owidth, oheight, iwidth, iheight );
+ if ( alpha != NULL )
+ {
+ mlt_properties_set_data( properties, "alpha", alpha, owidth * ( oheight + 1 ), ( mlt_destructor )mlt_pool_release, NULL );
+ this->get_alpha_mask = NULL;
+ }
+
// Return the output
return output;
}
// Set the consumer progressive property
if ( progressive )
{
- mlt_properties_set_int( properties, "consumer_progressive", progressive );
+ mlt_properties_set_int( properties, "consumer_deinterlace", progressive );
mlt_properties_set_int( properties, "test_audio", 1 );
}
for ( i = 0; i < list->count; i ++ )
if ( mlt_properties_get( this, list->name[ i ] ) != NULL )
fprintf( output, ", %s=%s", list->name[ i ], mlt_properties_get( this, list->name[ i ] ) );
+ else
+ fprintf( output, ", %s=%p", list->name[ i ], mlt_properties_get_data( this, list->name[ i ], NULL ) );
fprintf( output, " ]" );
}
fprintf( stderr, "\n" );
return mlt_multitrack_track( mlt_tractor_multitrack( this ), index );
}
-static uint8_t *mlt_tractor_alpha_mask( mlt_frame frame )
-{
- return mlt_properties_get_data( mlt_frame_properties( frame ), "alpha", NULL );
-}
-
static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable )
{
uint8_t *data = NULL;
mlt_properties_set_int( frame_properties, "width", mlt_properties_get_int( properties, "width" ) );
mlt_properties_set_int( frame_properties, "height", mlt_properties_get_int( properties, "height" ) );
mlt_properties_set( frame_properties, "rescale.interp", mlt_properties_get( properties, "rescale.interp" ) );
+ if ( mlt_properties_get( properties, "distort" ) )
+ mlt_properties_set( frame_properties, "distort", mlt_properties_get( properties, "distort" ) );
mlt_properties_set_double( frame_properties, "aspect_ratio", mlt_properties_get_double( properties, "aspect_ratio" ) );
mlt_properties_set_double( frame_properties, "consumer_aspect_ratio", mlt_properties_get_double( properties, "consumer_aspect_ratio" ) );
- mlt_properties_set_int( frame_properties, "consumer_progressive", mlt_properties_get_double( properties, "consumer_progressive" ) );
mlt_properties_set_int( frame_properties, "consumer_deinterlace", mlt_properties_get_double( properties, "consumer_deinterlace" ) );
mlt_frame_get_image( frame, buffer, format, width, height, writable );
mlt_properties_set_data( properties, "image", *buffer, *width * *height * 2, NULL, NULL );
mlt_properties_set_int( properties, "width", *width );
mlt_properties_set_int( properties, "height", *height );
mlt_properties_set_double( properties, "aspect_ratio", mlt_frame_get_aspect_ratio( frame ) );
+ mlt_properties_set_int( properties, "progressive", mlt_properties_get_int( frame_properties, "progressive" ) );
+ if ( mlt_properties_get( frame_properties, "distort" ) )
+ mlt_properties_set( properties, "distort", mlt_properties_get( frame_properties, "distort" ) );
data = mlt_frame_get_alpha_mask( frame );
mlt_properties_set_data( properties, "alpha", data, 0, NULL, NULL );
- this->get_alpha_mask = mlt_tractor_alpha_mask;
return 0;
}
mlt_properties_set_data( frame_properties, "data_queue", data_queue, 0, NULL, NULL );
mlt_properties_set_int( frame_properties, "width", mlt_properties_get_int( video_properties, "width" ) );
mlt_properties_set_int( frame_properties, "height", mlt_properties_get_int( video_properties, "height" ) );
+ mlt_properties_set_int( frame_properties, "real_width", mlt_properties_get_int( video_properties, "real_width" ) );
+ mlt_properties_set_int( frame_properties, "real_height", mlt_properties_get_int( video_properties, "real_height" ) );
+ mlt_properties_set_int( frame_properties, "progressive", mlt_properties_get_int( video_properties, "progressive" ) );
mlt_properties_set_double( frame_properties, "aspect_ratio", mlt_properties_get_double( video_properties, "aspect_ratio" ) );
}
static mlt_consumer create_consumer( char *id, mlt_producer producer )
{
- char *arg = strchr( id, ':' );
+ char *arg = id != NULL ? strchr( id, ':' ) : NULL;
if ( arg != NULL )
*arg ++ = '\0';
mlt_consumer consumer = mlt_factory_consumer( id, arg );
// If we have no consumer, default to sdl
if ( store == NULL && consumer == NULL )
- consumer = create_consumer( "sdl", inigo );
+ consumer = create_consumer( NULL, inigo );
if ( consumer != NULL && store == NULL )
{
{
struct hostent *he;
connection_t *connection = arg;
+ mlt_properties owner = connection->owner;
char address[ 512 ];
char command[ 1024 ];
int fd = connection->fd;
while( !error && connection_read( fd, command, 1024 ) )
{
+ response = NULL;
+
if ( !strncmp( command, "PUSH ", 5 ) )
{
char temp[ 20 ];
buffer[ bytes ] = '\0';
if ( bytes > 0 && total == bytes )
service = ( mlt_service )mlt_factory_producer( "westley-xml", buffer );
- response = valerie_parser_push( parser, command, service );
+ mlt_events_fire( owner, "push-received", &response, command, service, NULL );
+ if ( response == NULL )
+ response = valerie_parser_push( parser, command, service );
error = connection_send( fd, response );
valerie_response_close( response );
mlt_service_close( service );
}
else if ( strncmp( command, "STATUS", 6 ) )
{
- response = valerie_parser_execute( parser, command );
+ mlt_events_fire( owner, "command-received", &response, command, NULL );
+ if ( response == NULL )
+ response = valerie_parser_execute( parser, command );
miracle_log( LOG_INFO, "%s \"%s\" %d", address, command, valerie_response_get_error_code( response ) );
error = connection_send( fd, response );
valerie_response_close( response );
typedef struct
{
+ mlt_properties owner;
int fd;
struct sockaddr_in sin;
valerie_parser parser;
#define VERSION "0.0.1"
+static void miracle_command_received( mlt_listener listener, mlt_properties owner, miracle_server this, void **args )
+{
+ if ( listener != NULL )
+ listener( owner, this, ( valerie_response ** )args[ 0 ], ( char * )args[ 1 ] );
+}
+
+static void miracle_push_received( mlt_listener listener, mlt_properties owner, miracle_server this, void **args )
+{
+ if ( listener != NULL )
+ listener( owner, this, ( valerie_response ** )args[ 0 ], ( char * )args[ 1 ], ( mlt_service )args[ 2 ] );
+}
+
/** Initialise a server structure.
*/
{
miracle_server server = malloc( sizeof( miracle_server_t ) );
if ( server != NULL )
- {
memset( server, 0, sizeof( miracle_server_t ) );
+ if ( server != NULL && mlt_properties_init( &server->parent, server ) == 0 )
+ {
server->id = id;
server->port = DEFAULT_TCP_PORT;
server->socket = -1;
+ mlt_events_init( &server->parent );
+ mlt_events_register( &server->parent, "command-received", ( mlt_transmitter )miracle_command_received );
+ mlt_events_register( &server->parent, "push-received", ( mlt_transmitter )miracle_push_received );
}
return server;
}
our server thread. The thread should free this when it terminates. */
tmp = (connection_t*) malloc( sizeof(connection_t) );
+ tmp->owner = &server->parent;
tmp->parser = server->parser;
tmp->fd = accept( server->socket, (struct sockaddr*) &(tmp->sin), &socksize );
void miracle_server_close( miracle_server server )
{
- if ( server != NULL )
+ if ( server != NULL && mlt_properties_dec_ref( &server->parent ) <= 0 )
{
+ mlt_properties_close( &server->parent );
miracle_server_shutdown( server );
free( server );
}
typedef struct
{
+ struct mlt_properties_s parent;
char *id;
int port;
int socket;
return 0;
}
+static void scale_alpha( mlt_frame this, int iwidth, int iheight, int owidth, int oheight )
+{
+ uint8_t *input = mlt_frame_get_alpha_mask( this );
+
+ if ( input != NULL )
+ {
+ uint8_t *output = mlt_pool_alloc( owidth * oheight );
+
+ // Derived coordinates
+ int dy, dx;
+
+ // Calculate ranges
+ int out_x_range = owidth / 2;
+ int out_y_range = oheight / 2;
+ int in_x_range = iwidth / 2;
+ int in_y_range = iheight / 2;
+
+ // Output pointers
+ register uint8_t *out_line = output;
+ register uint8_t *out_ptr;
+
+ // Calculate a middle pointer
+ uint8_t *in_middle = input + iwidth * in_y_range + in_x_range;
+ uint8_t *in_line;
+
+ // Generate the affine transform scaling values
+ register int scale_width = ( iwidth << 16 ) / owidth;
+ register int scale_height = ( iheight << 16 ) / oheight;
+ register int base = 0;
+
+ int outer = out_x_range * scale_width;
+ int bottom = out_y_range * scale_height;
+
+ // Loop for the entirety of our output height.
+ for ( dy = - bottom; dy < bottom; dy += scale_height )
+ {
+ // Start at the beginning of the line
+ out_ptr = out_line;
+
+ // Pointer to the middle of the input line
+ in_line = in_middle + ( dy >> 16 ) * iwidth;
+
+ // Loop for the entirety of our output row.
+ for ( dx = - outer; dx < outer; dx += scale_width )
+ {
+ base = dx >> 15;
+ *out_ptr ++ = *( in_line + base );
+ }
+
+ // Move to next output line
+ out_line += owidth;
+ }
+
+ this->get_alpha_mask = NULL;
+ mlt_properties_set_data( mlt_frame_properties( this ), "alpha", output, 0, mlt_pool_release, NULL );
+ }
+}
+
/** Do it :-).
*/
}
// There can be problems with small images - avoid them (by hacking - gah)
- if ( *width >= 2 && *height >= 6 )
+ if ( *width >= 6 && *height >= 6 )
{
int iwidth = *width;
int iheight = *height;
// Get the image as requested
mlt_frame_get_image( this, image, format, &iwidth, &iheight, writable );
-
+
// Get rescale interpretation again, in case the producer wishes to override scaling
interps = mlt_properties_get( properties, "rescale.interp" );
scaler_method( this, image, *format, mlt_image_yuv422, iwidth, iheight, owidth, oheight );
*width = owidth;
*height = oheight;
+
+ // Scale the alpha
+ scale_alpha( this, iwidth, iheight, owidth, oheight );
}
else if ( *format == mlt_image_rgb24 && wanted_format == mlt_image_rgb24 )
{
// Return the output
*width = owidth;
*height = oheight;
+
+ // Scale the alpha
+ scale_alpha( this, iwidth, iheight, owidth, oheight );
}
else if ( *format == mlt_image_rgb24 || *format == mlt_image_rgb24a )
{
*format = mlt_image_yuv422;
*width = owidth;
*height = oheight;
+
+ // Scale the alpha
+ scale_alpha( this, iwidth, iheight, owidth, oheight );
}
else
{
return 0;
}
-static uint8_t *producer_get_alpha_mask( mlt_frame this )
-{
- // Obtain properties of frame
- mlt_properties properties = mlt_frame_properties( this );
-
- // Return the alpha mask
- return mlt_properties_get_data( properties, "alpha", NULL );
-}
-
/** Filter processing.
*/
// Push the get image method
mlt_frame_push_service( frame, filter_get_image );
- // Set alpha call back
- frame->get_alpha_mask = producer_get_alpha_mask;
-
return frame;
}
// Set the b frame to be in the same position and have same consumer requirements
mlt_frame_set_position( b_frame, position );
mlt_properties_set_double( b_props, "consumer_aspect_ratio", mlt_properties_get_double( a_props, "consumer_aspect_ratio" ) );
- mlt_properties_set_int( b_props, "consumer_progressive", mlt_properties_get_double( a_props, "consumer_progressive" ) );
+ mlt_properties_set_int( b_props, "consumer_deinterlace", mlt_properties_get_double( a_props, "consumer_deinterlace" ) );
+
+ if ( mlt_properties_get_int( properties, "distort" ) )
+ {
+ mlt_properties_set( mlt_transition_properties( composite ), "distort", "true" );
+ mlt_properties_set( a_props, "distort", "true" );
+ mlt_properties_set( b_props, "distort", "true" );
+ }
if ( mlt_properties_get_int( properties, "reverse" ) == 0 )
{
}
else
{
+ char temp[ 132 ];
+ int count = 0;
+ uint8_t *alpha = NULL;
mlt_transition_process( composite, b_frame, frame );
+ mlt_properties_set_int( a_props, "consumer_deinterlace", 1 );
+ mlt_properties_set_int( b_props, "consumer_deinterlace", 1 );
mlt_properties_set( a_props, "rescale.interp", "nearest" );
mlt_properties_set( b_props, "rescale.interp", "nearest" );
- mlt_service_apply_filters( mlt_filter_service( this ), frame, 0 );
+ mlt_service_apply_filters( mlt_filter_service( this ), b_frame, 0 );
error = mlt_frame_get_image( b_frame, image, format, width, height, 1 );
- mlt_properties_set_data( b_props, "image", *image, 0, NULL, NULL );
- mlt_properties_set_data( a_props, "image", *image, *width * *height * 2, mlt_pool_release, NULL );
+ alpha = mlt_frame_get_alpha_mask( b_frame );
+ mlt_properties_set_data( a_props, "image", *image, *width * *height * 2, NULL, NULL );
+ mlt_properties_set_data( a_props, "alpha", alpha, *width * *height, NULL, NULL );
mlt_properties_set_int( a_props, "width", *width );
mlt_properties_set_int( a_props, "height", *height );
+ mlt_properties_set_int( a_props, "progressive", 1 );
+ mlt_properties_inc_ref( b_props );
+ strcpy( temp, "_b_frame" );
+ while( mlt_properties_get_data( a_props, temp, NULL ) != NULL )
+ sprintf( temp, "_b_frame%d", count ++ );
+ mlt_properties_set_data( a_props, temp, b_frame, 0, ( mlt_destructor )mlt_frame_close, NULL );
}
}
mlt_properties b_props = mlt_frame_properties( b_frame );
mlt_properties properties = mlt_transition_properties( this );
- if ( mlt_properties_get( properties, "distort" ) == NULL && geometry->distort == 0 )
+ if ( mlt_properties_get( properties, "distort" ) == NULL && mlt_properties_get( b_props, "distort" ) == NULL && geometry->distort == 0 )
{
// Adjust b_frame pixel aspect
int normalised_width = geometry->w;
// Assign this position to the b frame
mlt_frame_set_position( b_frame, frame_position );
+ mlt_properties_set( b_props, "distort", "true" );
// Return the frame
return b_frame;
// Since we are the consumer of the b_frame, we must pass along these
// consumer properties from the a_frame
- mlt_properties_set_double( b_props, "consumer_progressive", mlt_properties_get_double( a_props, "consumer_progressive" ) );
+ mlt_properties_set_double( b_props, "consumer_deinterlace", mlt_properties_get_double( a_props, "consumer_deinterlace" ) );
mlt_properties_set_double( b_props, "consumer_aspect_ratio", mlt_properties_get_double( a_props, "consumer_aspect_ratio" ) );
// Special case for titling...
uint8_t *src = image_b;
uint8_t *alpha = mlt_frame_get_alpha_mask( b_frame );
int progressive =
- mlt_properties_get_int( a_props, "consumer_progressive" ) ||
+ mlt_properties_get_int( a_props, "consumer_deinterlace" ) ||
mlt_properties_get_int( properties, "progressive" );
int field;
int32_t weigh = weight * ( 1 << 16 );
int32_t weigh_complement = ( 1 - weight ) * ( 1 << 16 );
+ if ( mlt_properties_get( &this->parent, "distort" ) )
+ mlt_properties_set( &that->parent, "distort", mlt_properties_get( &this->parent, "distort" ) );
+ mlt_properties_set_int( &that->parent, "consumer_deinterlace", mlt_properties_get_int( &this->parent, "consumer_deinterlace" ) );
mlt_frame_get_image( this, &p_dest, &format, &width, &height, 1 );
mlt_frame_get_image( that, &p_src, &format, &width_src, &height_src, 0 );
format_src = mlt_image_yuv422;
format_dest = mlt_image_yuv422;
+ if ( mlt_properties_get( &a_frame->parent, "distort" ) )
+ mlt_properties_set( &b_frame->parent, "distort", mlt_properties_get( &a_frame->parent, "distort" ) );
+ mlt_properties_set_int( &b_frame->parent, "consumer_deinterlace", mlt_properties_get_int( &a_frame->parent, "consumer_deinterlace" ) );
mlt_frame_get_image( a_frame, &p_dest, &format_dest, &width_dest, &height_dest, 1 );
mlt_frame_get_image( b_frame, &p_src, &format_src, &width_src, &height_src, 0 );
float luma_softness = mlt_properties_get_double( properties, "softness" );
int progressive =
- mlt_properties_get_int( a_props, "consumer_progressive" ) ||
+ mlt_properties_get_int( a_props, "consumer_deinterlace" ) ||
mlt_properties_get_int( properties, "progressive" ) ||
mlt_properties_get_int( b_props, "luma.progressive" );
int top_field_first = mlt_properties_get_int( b_props, "top_field_first" );
int y_offset = ( int )result.h >> 1;
uint8_t *alpha = mlt_frame_get_alpha_mask( b_frame );
+ uint8_t *mask = mlt_pool_alloc( b_width * b_height );
+ uint8_t *pmask = mask;
float mix;
affine_t affine;
dz = MapZ( affine.matrix, 0, 0 );
+ if ( mask != NULL )
+ memset( mask, 0, b_width * b_height );
+
for ( y = lower_y; y < upper_y; y ++ )
{
p = q;
{
if ( alpha == NULL )
{
+ *pmask ++ = 255;
dx += dx & 1;
*p ++ = *( b_image + dy * b_stride + ( dx << 1 ) );
*p ++ = *( b_image + dy * b_stride + ( dx << 1 ) + ( ( x & 1 ) << 1 ) + 1 );
}
else
{
+ *pmask ++ = *( alpha + dy * b_width + dx );
mix = ( float )*( alpha + dy * b_width + dx ) / 255.0;
dx += dx & 1;
*p = *p * ( 1 - mix ) + mix * *( b_image + dy * b_stride + ( dx << 1 ) );
else
{
p += 2;
+ pmask ++;
}
}
q += a_stride;
}
+
+ b_frame->get_alpha_mask = NULL;
+ mlt_properties_set_data( b_props, "alpha", mask, 0, mlt_pool_release, NULL );
}
return 0;