* \file mlt_types.h
* \brief Provides forward definitions of all public types
*
- * Copyright (C) 2003-2009 Ushodaya Enterprises Limited
+ * Copyright (C) 2003-2012 Ushodaya Enterprises Limited
* \author Charles Yates <charles.yates@pandora.be>
*
* This library is free software; you can redistribute it and/or
mlt_audio_s16 = 1, /**< signed 16-bit interleaved PCM */
mlt_audio_s32, /**< signed 32-bit non-interleaved PCM */
mlt_audio_float, /**< 32-bit non-interleaved floating point */
- mlt_audio_s32le, /**< signed 32-bit interleaved PCM, may only used by producers */
- mlt_audio_f32le /**< 32-bit interleaved floating point, may only be used by producers */
+ mlt_audio_s32le, /**< signed 32-bit interleaved PCM */
+ mlt_audio_f32le /**< 32-bit interleaved floating point */
}
mlt_audio_format;
#if LIBAVUTIL_VERSION_INT >= ((50<<16)+(8<<8)+0)
#include <libavutil/pixdesc.h>
#endif
+#if LIBAVUTIL_VERSION_INT >= ((50<<16)+(38<<8)+0)
+#include <libavutil/samplefmt.h>
+#endif
#include <libavutil/mathematics.h>
#if LIBAVUTIL_VERSION_INT < (50<<16)
typedef struct
{
- int16_t *buffer;
+ uint8_t *buffer;
int size;
int used;
double time;
return fifo;
}
-// sample_fifo_clear and check are temporarily aborted (not working as intended)
-
-void sample_fifo_clear( sample_fifo fifo, double time )
-{
- int words = ( float )( time - fifo->time ) * fifo->frequency * fifo->channels;
- if ( ( int )( ( float )time * 100 ) < ( int )( ( float )fifo->time * 100 ) && fifo->used > words && words > 0 )
- {
- memmove( fifo->buffer, &fifo->buffer[ words ], ( fifo->used - words ) * sizeof( int16_t ) );
- fifo->used -= words;
- fifo->time = time;
- }
- else if ( ( int )( ( float )time * 100 ) != ( int )( ( float )fifo->time * 100 ) )
- {
- fifo->used = 0;
- fifo->time = time;
- }
-}
-
-void sample_fifo_check( sample_fifo fifo, double time )
-{
- if ( fifo->used == 0 )
- {
- if ( ( int )( ( float )time * 100 ) < ( int )( ( float )fifo->time * 100 ) )
- fifo->time = time;
- }
-}
-
-void sample_fifo_append( sample_fifo fifo, int16_t *samples, int count )
+// count is the number of samples multiplied by the number of bytes per sample
+void sample_fifo_append( sample_fifo fifo, uint8_t *samples, int count )
{
if ( ( fifo->size - fifo->used ) < count )
{
fifo->size += count * 5;
- fifo->buffer = realloc( fifo->buffer, fifo->size * sizeof( int16_t ) );
+ fifo->buffer = realloc( fifo->buffer, fifo->size );
}
- memcpy( &fifo->buffer[ fifo->used ], samples, count * sizeof( int16_t ) );
+ memcpy( &fifo->buffer[ fifo->used ], samples, count );
fifo->used += count;
}
return fifo->used;
}
-int sample_fifo_fetch( sample_fifo fifo, int16_t *samples, int count )
+int sample_fifo_fetch( sample_fifo fifo, uint8_t *samples, int count )
{
if ( count > fifo->used )
count = fifo->used;
- memcpy( samples, fifo->buffer, count * sizeof( int16_t ) );
+ memcpy( samples, fifo->buffer, count );
fifo->used -= count;
- memmove( fifo->buffer, &fifo->buffer[ count ], fifo->used * sizeof( int16_t ) );
+ memmove( fifo->buffer, &fifo->buffer[ count ], fifo->used );
fifo->time += ( double )count / fifo->channels / fifo->frequency;
mlt_properties_set_double( properties, "muxdelay", 0.7 );
mlt_properties_set_double( properties, "muxpreload", 0.5 );
+ // Some AVOption defaults we like
+ mlt_properties_set( properties, "strict", "experimental" );
+
// Ensure termination at end of the stream
mlt_properties_set_int( properties, "terminate_on_pause", 1 );
}
}
+static int get_mlt_audio_format( int av_sample_fmt )
+{
+ switch ( av_sample_fmt )
+ {
+ case AV_SAMPLE_FMT_S32:
+ return mlt_audio_s32le;
+ case AV_SAMPLE_FMT_FLT:
+ return mlt_audio_f32le;
+#if LIBAVUTIL_VERSION_INT >= ((51<<16)+(17<<8)+0)
+ case AV_SAMPLE_FMT_S32P:
+ return mlt_audio_s32;
+ case AV_SAMPLE_FMT_FLTP:
+ return mlt_audio_float;
+#endif
+ default:
+ return mlt_audio_s16;
+ }
+}
+
+static int pick_sample_fmt( mlt_properties properties, AVCodec *codec )
+{
+ int sample_fmt = AV_SAMPLE_FMT_S16;
+ const char *format = mlt_properties_get( properties, "mlt_audio_format" );
+ const int *p = codec->sample_fmts;
+
+ // get default av_sample_fmt from mlt_audio_format
+ if ( format )
+ {
+ if ( !strcmp( format, "s32le" ) )
+ sample_fmt = AV_SAMPLE_FMT_S32;
+ else if ( !strcmp( format, "f32le" ) )
+ sample_fmt = AV_SAMPLE_FMT_FLT;
+#if LIBAVUTIL_VERSION_INT >= ((51<<16)+(17<<8)+0)
+ else if ( !strcmp( format, "s32" ) )
+ sample_fmt = AV_SAMPLE_FMT_S32P;
+ else if ( !strcmp( format, "float" ) )
+ sample_fmt = AV_SAMPLE_FMT_FLTP;
+#endif
+ }
+ // check if codec supports our mlt_audio_format
+ for ( ; *p != -1; p++ )
+ {
+ if ( *p == sample_fmt )
+ return sample_fmt;
+ }
+ // no match - pick first one we support
+ for ( p = codec->sample_fmts; *p != -1; p++ )
+ {
+ switch (*p)
+ {
+ case AV_SAMPLE_FMT_S16:
+ case AV_SAMPLE_FMT_S32:
+ case AV_SAMPLE_FMT_FLT:
+#if LIBAVUTIL_VERSION_INT >= ((51<<16)+(17<<8)+0)
+ case AV_SAMPLE_FMT_S32P:
+ case AV_SAMPLE_FMT_FLTP:
+#endif
+ return *p;
+ default:
+ break;
+ }
+ }
+ mlt_log_error( properties, "audio codec sample_fmt not compatible" );
+
+ return AV_SAMPLE_FMT_NONE;
+}
+
/** Add an audio output stream
*/
c->codec_id = codec->id;
c->codec_type = CODEC_TYPE_AUDIO;
- c->sample_fmt = SAMPLE_FMT_S16;
+ c->sample_fmt = pick_sample_fmt( properties, codec );
#if 0 // disabled until some audio codecs are multi-threaded
// Setup multi-threading
int img_height = height;
// Get default audio properties
- mlt_audio_format aud_fmt = mlt_audio_s16;
int channels = mlt_properties_get_int( properties, "channels" );
int total_channels = channels;
int frequency = mlt_properties_get_int( properties, "frequency" );
- int16_t *pcm = NULL;
+ void *pcm = NULL;
int samples = 0;
// AVFormat audio buffer and frame size
mlt_image_format img_fmt = mlt_image_yuv422;
// For receiving audio samples back from the fifo
- int16_t *audio_buf_1 = av_malloc( AUDIO_ENCODE_BUFFER_SIZE );
- int16_t *audio_buf_2 = NULL;
+ uint8_t *audio_buf_1 = av_malloc( AUDIO_ENCODE_BUFFER_SIZE );
+ uint8_t *audio_buf_2 = NULL;
int count = 0;
// Allocate the context
}
mlt_properties_set_int( properties, "channels", total_channels );
+ // Audio format is determined when adding the audio stream
+ mlt_audio_format aud_fmt = mlt_audio_none;
+ if ( audio_st[0] )
+ aud_fmt = get_mlt_audio_format( audio_st[0]->codec->sample_fmt );
+ int sample_bytes = mlt_audio_format_size( aud_fmt, 1, 1 );
+ sample_bytes = sample_bytes ? sample_bytes : 1; // prevent divide by zero
+
// Set the parameters (even though we have none...)
#if LIBAVFORMAT_VERSION_INT < ((53<<16)+(2<<8)+0)
if ( av_set_parameters(oc, NULL) >= 0 )
{
samples = mlt_sample_calculator( fps, frequency, count ++ );
channels = total_channels;
- mlt_frame_get_audio( frame, (void**) &pcm, &aud_fmt, &frequency, &channels, &samples );
+ mlt_frame_get_audio( frame, &pcm, &aud_fmt, &frequency, &channels, &samples );
// Save the audio channel remap properties for later
mlt_properties_pass( frame_meta_properties, frame_properties, "meta.map.audio." );
// Silence if not normal forward speed
if ( mlt_properties_get_double( frame_properties, "_speed" ) != 1.0 )
- memset( pcm, 0, samples * channels * 2 );
+ memset( pcm, 0, samples * channels * sample_bytes );
// Append the samples
- sample_fifo_append( fifo, pcm, samples * channels );
+ sample_fifo_append( fifo, pcm, samples * channels * sample_bytes );
total_time += ( samples * 1000000 ) / frequency;
if ( !video_st )
if ( !video_st || ( video_st && audio_st[0] && audio_pts < video_pts ) )
{
// Write audio
- if ( ( video_st && terminated ) || ( channels * audio_input_frame_size ) < sample_fifo_used( fifo ) )
+ if ( ( video_st && terminated ) || ( channels * audio_input_frame_size ) < sample_fifo_used( fifo ) / sample_bytes )
{
int j = 0; // channel offset into interleaved source buffer
- int n = FFMIN( FFMIN( channels * audio_input_frame_size, sample_fifo_used( fifo ) ), AUDIO_ENCODE_BUFFER_SIZE );
+ int n = FFMIN( FFMIN( channels * audio_input_frame_size, sample_fifo_used( fifo ) / sample_bytes ), AUDIO_ENCODE_BUFFER_SIZE );
// Get the audio samples
if ( n > 0 )
{
- sample_fifo_fetch( fifo, audio_buf_1, n );
+ sample_fifo_fetch( fifo, audio_buf_1, n * sample_bytes );
}
else if ( audio_codec_id == CODEC_ID_VORBIS && terminated )
{
// Optimized for single track and no channel remap
if ( !audio_st[1] && !mlt_properties_count( frame_meta_properties ) )
{
- pkt.size = avcodec_encode_audio( codec, audio_outbuf, audio_outbuf_size, audio_buf_1 );
+ pkt.size = avcodec_encode_audio( codec, audio_outbuf, audio_outbuf_size, (short*) audio_buf_1 );
}
else
{
// Interleave the audio buffer with the # channels for this stream/mapping.
for ( k = 0; k < map_channels; k++, j++, source_offset++, dest_offset++ )
{
- int16_t *src = audio_buf_1 + source_offset;
- int16_t *dest = audio_buf_2 + dest_offset;
+ void *src = audio_buf_1 + source_offset * sample_bytes;
+ void *dest = audio_buf_2 + dest_offset * sample_bytes;
int s = samples + 1;
while ( --s ) {
- *dest = *src;
- dest += current_channels;
- src += channels;
+ memcpy( dest, src, sample_bytes );
+ dest += current_channels * sample_bytes;
+ src += channels * sample_bytes;
}
}
}
dest_offset += current_channels;
}
}
- pkt.size = avcodec_encode_audio( codec, audio_outbuf, audio_outbuf_size, audio_buf_2 );
+ pkt.size = avcodec_encode_audio( codec, audio_outbuf, audio_outbuf_size, (short*) audio_buf_2 );
}
// Write the compressed frame in the media file
long passed = time_difference( &ante );
if ( fifo != NULL )
{
- long pending = ( ( ( long )sample_fifo_used( fifo ) * 1000 ) / frequency ) * 1000;
+ long pending = ( ( ( long )sample_fifo_used( fifo ) / sample_bytes * 1000 ) / frequency ) * 1000;
passed -= pending;
}
if ( passed < total_time )
pkt.size = 0;
if ( /*( c->capabilities & CODEC_CAP_SMALL_LAST_FRAME ) &&*/
- ( channels * audio_input_frame_size < sample_fifo_used( fifo ) ) )
+ ( channels * audio_input_frame_size < sample_fifo_used( fifo ) / sample_bytes ) )
{
- sample_fifo_fetch( fifo, audio_buf_1, channels * audio_input_frame_size );
- pkt.size = avcodec_encode_audio( c, audio_outbuf, audio_outbuf_size, audio_buf_1 );
+ sample_fifo_fetch( fifo, audio_buf_1, channels * audio_input_frame_size * sample_bytes );
+ pkt.size = avcodec_encode_audio( c, audio_outbuf, audio_outbuf_size, (short*) audio_buf_1 );
}
if ( pkt.size <= 0 )
pkt.size = avcodec_encode_audio( c, audio_outbuf, audio_outbuf_size, NULL );
/*
* filter_audiochannels.c -- convert from one audio format to another
- * Copyright (C) 2009 Ushodaya Enterprises Limited
+ * Copyright (C) 2009-2012 Ushodaya Enterprises Limited
* Author: Dan Dennedy <dan@dennedy.org>
*
* This library is free software; you can redistribute it and/or
{
for ( j = 0; j < *channels; j++ )
{
- new_buffer[ ( i * *channels ) + j ] = ((int16_t*)(*buffer))[ ( i * channels_avail ) + k ];
+ new_buffer[ ( i * *channels ) + j ] = ((int16_t*)(*buffer))[ ( i * channels_avail ) + k ];
+ k = ( k + 1 ) % channels_avail;
+ }
+ }
+ }
+ else if ( *format == mlt_audio_s32le || *format == mlt_audio_f32le )
+ {
+ int32_t *p = (int32_t*) new_buffer;
+ int i, j, k = 0;
+ for ( i = 0; i < *samples; i++ )
+ {
+ for ( j = 0; j < *channels; j++ )
+ {
+ p[ ( i * *channels ) + j ] = ((int32_t*)(*buffer))[ ( i * channels_avail ) + k ];
k = ( k + 1 ) % channels_avail;
}
}
}
else
{
- // non-interleaved
+ // non-interleaved - s32 or float
int size_avail = mlt_audio_format_size( *format, *samples, channels_avail );
int32_t *p = (int32_t*) new_buffer;
int i = *channels / channels_avail;
/*
* filter_audioconvert.c -- convert from one audio format to another
- * Copyright (C) 2009 Ushodaya Enterprises Limited
+ * Copyright (C) 2009-2012 Ushodaya Enterprises Limited
* Author: Dan Dennedy <dan@dennedy.org>
*
* This library is free software; you can redistribute it and/or
error = 0;
break;
}
+ case mlt_audio_s32le:
+ {
+ int32_t *buffer = mlt_pool_alloc( size );
+ int32_t *p = buffer;
+ int16_t *q = (int16_t*) *audio;
+ int i = samples * channels + 1;
+ while ( --i )
+ *p++ = (int32_t) *q++ << 16;
+ *audio = buffer;
+ error = 0;
+ break;
+ }
+ case mlt_audio_f32le:
+ {
+ float *buffer = mlt_pool_alloc( size );
+ float *p = buffer;
+ int16_t *q = (int16_t*) *audio;
+ int i = samples * channels + 1;
+ while ( --i )
+ {
+ float f = (float)( *q++ ) / 32768.0;
+ f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f;
+ *p++ = f;
+ }
+ *audio = buffer;
+ error = 0;
+ break;
+ }
default:
break;
}
error = 0;
break;
}
+ case mlt_audio_s32le:
+ {
+ int32_t *buffer = mlt_pool_alloc( size );
+ int32_t *p = buffer;
+ int32_t *q = (int32_t*) *audio;
+ int s, c;
+ for ( s = 0; s < samples; s++ )
+ for ( c = 0; c < channels; c++ )
+ *p++ = *( q + c * samples + s );
+ *audio = buffer;
+ error = 0;
+ break;
+ }
+ case mlt_audio_f32le:
+ {
+ float *buffer = mlt_pool_alloc( size );
+ float *p = buffer;
+ int32_t *q = (int32_t*) *audio;
+ int s, c;
+ for ( s = 0; s < samples; s++ )
+ for ( c = 0; c < channels; c++ )
+ {
+ float f = (float)( *( q + c * samples + s ) ) / 2147483648.0;
+ f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f;
+ *p++ = f;
+ }
+ *audio = buffer;
+ error = 0;
+ break;
+ }
default:
break;
}
error = 0;
break;
}
+ case mlt_audio_s32le:
+ {
+ int32_t *buffer = mlt_pool_alloc( size );
+ int32_t *p = buffer;
+ float *q = (float*) *audio;
+ int s, c;
+ for ( s = 0; s < samples; s++ )
+ for ( c = 0; c < channels; c++ )
+ {
+ float f = *( q + c * samples + s );
+ f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f;
+ *p++ = ( f > 0 ? 2147483647LL : 2147483648LL ) * f;
+ }
+ *audio = buffer;
+ error = 0;
+ break;
+ }
+ case mlt_audio_f32le:
+ {
+ float *buffer = mlt_pool_alloc( size );
+ float *p = buffer;
+ float *q = (float*) *audio;
+ int s, c;
+ for ( s = 0; s < samples; s++ )
+ for ( c = 0; c < channels; c++ )
+ *p++ = *( q + c * samples + s );
+ *audio = buffer;
+ error = 0;
+ break;
+ }
default:
break;
}
error = 0;
break;
}
+ case mlt_audio_f32le:
+ {
+ float *buffer = mlt_pool_alloc( size );
+ float *p = buffer;
+ int32_t *q = (int32_t*) *audio;
+ int i = samples * channels + 1;
+ while ( --i )
+ *p++ = (float)( *q++ ) / 2147483648.0;
+ *audio = buffer;
+ error = 0;
+ break;
+ }
default:
break;
}
error = 0;
break;
}
+ case mlt_audio_s32le:
+ {
+ int32_t *buffer = mlt_pool_alloc( size );
+ int32_t *p = buffer;
+ float *q = (float*) *audio;
+ int i = samples * channels + 1;
+ while ( --i )
+ {
+ float f = *q++;
+ f = f > 1.0 ? 1.0 : f < -1.0 ? -1.0 : f;
+ *p++ = ( f > 0 ? 2147483647LL : 2147483648LL ) * f;
+ }
+ *audio = buffer;
+ error = 0;
+ break;
+ }
default:
break;
}
/*
* filter_channelcopy.c -- copy one audio channel to another
- * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
+ * Copyright (C) 2003-2012 Ushodaya Enterprises Limited
* Author: Dan Dennedy <dan@dennedy.org>
*
* This library is free software; you can redistribute it and/or
}
break;
}
+ case mlt_audio_s32le:
+ case mlt_audio_f32le:
+ {
+ int32_t *f = (int32_t*) *buffer + from;
+ int32_t *t = (int32_t*) *buffer + to;
+ int32_t x;
+ int i;
+
+ if ( swap )
+ for ( i = 0; i < *samples; i++, f += *channels, t += *channels )
+ {
+ x = *t;
+ *t = *f;
+ *f = x;
+ }
+ else
+ for ( i = 0; i < *samples; i++, f += *channels, t += *channels )
+ *t = *f;
+ break;
+ }
case mlt_audio_float:
{
float *f = (float*) *buffer + from * *samples;
/*
* filter_mono.c -- mix all channels to a mono signal across n channels
- * Copyright (C) 2003-2009 Ushodaya Enterprises Limited
+ * Copyright (C) 2003-2012 Ushodaya Enterprises Limited
* Author: Dan Dennedy <dan@dennedy.org>
*
* This library is free software; you can redistribute it and/or
*buffer = new_buffer;
break;
}
+ case mlt_audio_s32le:
+ {
+ int32_t *new_buffer = mlt_pool_alloc( size );
+ for ( i = 0; i < *samples; i++ )
+ {
+ int32_t mixdown = 0;
+ for ( j = 0; j < *channels; j++ )
+ mixdown += ((int32_t*) *buffer)[ ( i * *channels ) + j ] / *channels;
+ for ( j = 0; j < channels_out; j++ )
+ new_buffer[ ( i * channels_out ) + j ] = mixdown;
+ }
+ *buffer = new_buffer;
+ break;
+ }
+ case mlt_audio_f32le:
+ {
+ float *new_buffer = mlt_pool_alloc( size );
+ for ( i = 0; i < *samples; i++ )
+ {
+ float mixdown = 0;
+ for ( j = 0; j < *channels; j++ )
+ mixdown += ((float*) *buffer)[ ( i * *channels ) + j ] / *channels;
+ for ( j = 0; j < channels_out; j++ )
+ new_buffer[ ( i * channels_out ) + j ] = mixdown;
+ }
+ *buffer = new_buffer;
+ break;
+ }
case mlt_audio_s32:
{
int32_t *new_buffer = mlt_pool_alloc( size );
break;
default:
result = 0;
- mlt_log_warning( container, "Producer defined inside something that isn't a container\n" );
+ mlt_log_warning( NULL, "[producer_xml] Producer defined inside something that isn't a container\n" );
break;
};
}
else
{
- mlt_log_warning( tractor, "Invalid state for tractor\n" );
+ mlt_log_error( NULL, "[producer_xml] Invalid state for tractor\n" );
}
}
}
else
{
- mlt_log_warning( parent, "Invalid multitrack position\n" );
+ mlt_log_error( NULL, "[producer_xml] Invalid multitrack position\n" );
}
}
mlt_service service = context_pop_service( context, &type );
if ( service == NULL || type != mlt_multitrack_type )
- mlt_log_warning( service, "End multitrack in the wrong state...\n" );
+ mlt_log_error( NULL, "[producer_xml] End multitrack in the wrong state...\n" );
}
static void on_start_playlist( deserialise_context context, const xmlChar *name, const xmlChar **atts)
}
else
{
- mlt_log_warning( service, "Invalid state of playlist end %d\n", type );
+ mlt_log_error( NULL, "[producer_xml] Invalid state of playlist end %d\n", type );
}
}
if ( !producer && resource )
producer = MLT_SERVICE( mlt_factory_producer( context->profile, NULL, resource ) );
if ( !producer )
- mlt_log_warning( service, "failed to load producer \"%s\"\n", resource );
+ mlt_log_error( NULL, "[producer_xml] failed to load producer \"%s\"\n", resource );
if ( !producer )
producer = MLT_SERVICE( mlt_factory_producer( context->profile, NULL, "+INVALID.txt" ) );
if ( !producer )
}
else
{
- mlt_log_warning( service, "blank without a playlist - a definite no no\n" );
+ mlt_log_error( NULL, "[producer_xml] blank without a playlist - a definite no no\n" );
}
}
}
else
{
- mlt_log_warning( parent, "Entry not part of a playlist...\n" );
+ mlt_log_error( NULL, "[producer_xml] Entry not part of a playlist...\n" );
}
context_push_service( context, parent, parent_type );
if ( entry == NULL && entry_type != mlt_entry_type )
{
- mlt_log_warning( entry, "Invalid state at end of entry\n" );
+ mlt_log_error( NULL, "[producer_xml] Invalid state at end of entry\n" );
}
}
else if ( parent_type == mlt_multitrack_type )
multitrack = MLT_MULTITRACK( parent );
else
- mlt_log_warning( track, "track contained in an invalid container\n" );
+ mlt_log_error( NULL, "[producer_xml] track contained in an invalid container\n" );
if ( multitrack != NULL )
{
}
else
{
- mlt_log_warning( track, "Invalid state at end of track\n" );
+ mlt_log_error( NULL, "[producer_xml] Invalid state at end of track\n" );
}
}
if ( !filter )
{
- mlt_log_warning( service, "failed to load filter \"%s\"\n", id );
+ mlt_log_error( NULL, "[producer_xml] failed to load filter \"%s\"\n", id );
if ( parent )
context_push_service( context, parent, parent_type );
mlt_service_close( service );
}
else
{
- mlt_log_warning( service, "filter closed with invalid parent...\n" );
+ mlt_log_error( NULL, "[producer_xml] filter closed with invalid parent...\n" );
}
// Close the dummy filter service
}
else
{
- mlt_log_warning( service, "Invalid top of stack on filter close\n" );
+ mlt_log_error( NULL, "[producer_xml] Invalid top of stack on filter close\n" );
}
}
if ( !effect )
{
- mlt_log_warning( service, "failed to load transition \"%s\"\n", id );
+ mlt_log_error( NULL, "[producer_xml] failed to load transition \"%s\"\n", id );
if ( parent )
context_push_service( context, parent, parent_type );
mlt_service_close( service );
}
else
{
- mlt_log_warning( service, "Misplaced transition - ignoring\n" );
+ mlt_log_warning( NULL, "[producer_xml] Misplaced transition - ignoring\n" );
}
// Put the parent back on the stack
}
else
{
- mlt_log_warning( service, "transition closed with invalid parent...\n" );
+ mlt_log_error( NULL, "[producer_xml] transition closed with invalid parent...\n" );
}
// Close the dummy filter service
}
else
{
- mlt_log_warning( service, "Invalid top of stack on transition close\n" );
+ mlt_log_error( NULL, "[producer_xml] Invalid top of stack on transition close\n" );
}
}
}
else
{
- mlt_log_warning( service, "Property without a service '%s'?\n", ( const char * )name );
+ mlt_log_error( NULL, "[producer_xml] Property without a service '%s'?\n", ( const char * )name );
}
}
}
else
{
- mlt_log_warning( service, "Property without a service '%s'??\n", (const char *)name );
+ mlt_log_error( NULL, "[producer_xml] Property without a service '%s'??\n", (const char *)name );
}
}
struct _xmlParserCtxt *xmlcontext = ( struct _xmlParserCtxt* )ctx;
deserialise_context context = ( deserialise_context )( xmlcontext->_private );
-//printf("on_start_element: %s\n", name );
if ( context->pass == 0 )
{
if ( xmlStrcmp( name, _x("mlt") ) == 0 ||
struct _xmlParserCtxt *xmlcontext = ( struct _xmlParserCtxt* )ctx;
deserialise_context context = ( deserialise_context )( xmlcontext->_private );
-//printf("on_end_element: %s\n", name );
if ( context->is_value == 1 && context->pass == 1 && xmlStrcmp( name, _x("property") ) != 0 )
context_pop_node( context );
else if ( xmlStrcmp( name, _x("multitrack") ) == 0 )
return e;
}
-/** Handle error messages from the parser.
-*/
-static void on_error( void * ctx, const char * msg, ...)
+static void on_error( void * ctx, const char * msg, ... )
{
- struct _xmlError* err_ptr = xmlCtxtGetLastError(ctx);
- mlt_log_error( NULL, "XML producer parse error: %s\trow: %d\tcol: %d\n",
- err_ptr->message, err_ptr->line, err_ptr->int2 );
+ struct _xmlError* err_ptr = xmlCtxtGetLastError( ctx );
+
+ switch( err_ptr->level )
+ {
+ case XML_ERR_WARNING:
+ mlt_log_warning( NULL, "[producer_xml] parse warning: %s\trow: %d\tcol: %d\n",
+ err_ptr->message, err_ptr->line, err_ptr->int2 );
+ break;
+ case XML_ERR_ERROR:
+ mlt_log_error( NULL, "[producer_xml] parse error: %s\trow: %d\tcol: %d\n",
+ err_ptr->message, err_ptr->line, err_ptr->int2 );
+ break;
+ default:
+ case XML_ERR_FATAL:
+ mlt_log_fatal( NULL, "[producer_xml] parse fatal: %s\trow: %d\tcol: %d\n",
+ err_ptr->message, err_ptr->line, err_ptr->int2 );
+ break;
+ }
}
/** Convert a hexadecimal character to its value.
// We need to track the number of registered filters
mlt_properties_set_int( context->destructors, "registered", 0 );
+ // Setup SAX callbacks for first pass
+ sax->startElement = on_start_element;
+ sax->warning = on_error;
+ sax->error = on_error;
+ sax->fatalError = on_error;
+
// Setup libxml2 SAX parsing
xmlInitParser();
xmlSubstituteEntitiesDefault( 1 );
xmlcontext->sax = sax;
xmlcontext->_private = ( void* )context;
xmlParseDocument( xmlcontext );
+ well_formed = xmlcontext->wellFormed;
// Cleanup after parsing
xmlcontext->sax = NULL;
context->stack_node_size = 0;
context->stack_service_size = 0;
+ // Bad xml - clean up and return NULL
+ if ( !well_formed )
+ {
+ mlt_properties_close( context->producer_map );
+ mlt_properties_close( context->destructors );
+ mlt_properties_close( context->params );
+ xmlFreeDoc( context->entity_doc );
+ free( context );
+ free( sax );
+ free( filename );
+ return NULL;
+ }
+
// Setup the second pass
context->pass ++;
if ( info == 0 )
return NULL;
}
- // Setup SAX callbacks
- sax->startElement = on_start_element;
+ // Setup SAX callbacks for second pass
sax->endElement = on_end_element;
sax->characters = on_characters;
sax->cdataBlock = on_characters;
sax->internalSubset = on_internal_subset;
sax->entityDecl = on_entity_declaration;
sax->getEntity = on_get_entity;
- sax->error = on_error;
- sax->fatalError = on_error;
// Parse
xmlcontext->sax = sax;