int colorspace;
pthread_mutex_t video_mutex;
pthread_mutex_t audio_mutex;
+ mlt_deque apackets;
+ mlt_deque vpackets;
+ pthread_mutex_t packets_mutex;
#ifdef VDPAU
struct
{
static void producer_set_up_audio( producer_avformat self, mlt_frame frame );
static void apply_properties( void *obj, mlt_properties properties, int flags );
static int video_codec_init( producer_avformat self, int index, mlt_properties properties );
+static void get_audio_streams_info( producer_avformat self );
#ifdef VDPAU
#include "vdpau.c"
mlt_producer_close( producer );
producer = NULL;
}
- else
+ else if ( self->seekable )
{
// Close the file to release resources for large playlists - reopen later as needed
avformat_lock();
- if ( self->dummy_context )
- av_close_input_file( self->dummy_context );
- self->dummy_context = NULL;
if ( self->audio_format )
av_close_input_file( self->audio_format );
self->audio_format = NULL;
{
if ( !URL ) return NULL;
- char *result = NULL;
+ const char *result = URL;
char *protocol = strdup( URL );
char *url = strchr( protocol, ':' );
{
// Truncate protocol string
url[0] = 0;
+ mlt_log_debug( NULL, "%s: protocol=%s resource=%s\n", __FUNCTION__, protocol, url + 1 );
// Lookup the format
*format = av_find_input_format( protocol );
}
}
free( protocol );
- return result ? strdup( result ) : strdup( URL );
+ return strdup( result );
}
static int get_basic_info( producer_avformat self, mlt_profile profile, const char *filename )
{
// Return an error code (0 == no error)
int error = 0;
+ mlt_properties properties = MLT_PRODUCER_PROPERTIES( self->parent );
// Lock the service
pthread_mutex_init( &self->audio_mutex, NULL );
pthread_mutex_init( &self->video_mutex, NULL );
+ pthread_mutex_init( &self->packets_mutex, NULL );
+ mlt_events_block( properties, self->parent );
pthread_mutex_lock( &self->audio_mutex );
pthread_mutex_lock( &self->video_mutex );
AVFormatParameters *params = NULL;
char *filename = parse_url( profile, URL, &format, ¶ms );
- // Now attempt to open the file
+ // Now attempt to open the file or device with filename
error = av_open_input_file( &self->video_format, filename, format, 0, params ) < 0;
+ if ( error )
+ // If the URL is a network stream URL, then we probably need to open with full URL
+ error = av_open_input_file( &self->video_format, URL, format, 0, params ) < 0;
+
+ // Set MLT properties onto video AVFormatContext
+ apply_properties( self->video_format, properties, AV_OPT_FLAG_DECODING_PARAM );
+#if LIBAVFORMAT_VERSION_MAJOR > 52
+ if ( self->video_format->iformat && self->video_format->iformat->priv_class && self->video_format->priv_data )
+ apply_properties( self->video_format->priv_data, properties, AV_OPT_FLAG_DECODING_PARAM );
+#endif
// Cleanup AVFormatParameters
if ( params )
// TODO: Is this really necessary?
if ( self->audio_index != -1 && self->video_index != -1 )
{
- // And open again for our audio context
- av_open_input_file( &self->audio_format, filename, NULL, 0, NULL );
- av_find_stream_info( self->audio_format );
+ if ( self->seekable )
+ {
+ // And open again for our audio context
+ av_open_input_file( &self->audio_format, filename, NULL, 0, NULL );
+ apply_properties( self->audio_format, properties, AV_OPT_FLAG_DECODING_PARAM );
+#if LIBAVFORMAT_VERSION_MAJOR > 52
+ if ( self->audio_format->iformat && self->audio_format->iformat->priv_class && self->audio_format->priv_data )
+ apply_properties( self->audio_format->priv_data, properties, AV_OPT_FLAG_DECODING_PARAM );
+#endif
+ av_find_stream_info( self->audio_format );
+ }
+ else
+ {
+ self->audio_format = self->video_format;
+ }
}
else if ( self->audio_index != -1 )
{
// Something has gone wrong
error = -1;
}
+ if ( self->audio_format && !self->audio_streams )
+ get_audio_streams_info( self );
}
}
if ( filename )
free( filename );
+ if ( !error )
+ {
+ self->apackets = mlt_deque_init();
+ self->vpackets = mlt_deque_init();
+ }
+
+ if ( self->dummy_context )
+ {
+ av_close_input_file( self->dummy_context );
+ self->dummy_context = NULL;
+ }
// Unlock the service
pthread_mutex_unlock( &self->audio_mutex );
pthread_mutex_unlock( &self->video_mutex );
+ mlt_events_unblock( properties, self->parent );
return error;
}
int audio_index = self->audio_index;
int video_index = self->video_index;
- mlt_events_block( properties, producer );
pthread_mutex_unlock( &self->audio_mutex );
pthread_mutex_unlock( &self->video_mutex );
producer_open( self, mlt_service_profile( MLT_PRODUCER_SERVICE(producer) ),
mlt_properties_get( properties, "resource" ) );
pthread_mutex_lock( &self->video_mutex );
pthread_mutex_lock( &self->audio_mutex );
- if ( self->dummy_context )
- {
- av_close_input_file( self->dummy_context );
- self->dummy_context = NULL;
- }
- mlt_events_unblock( properties, producer );
- apply_properties( self->video_format, properties, AV_OPT_FLAG_DECODING_PARAM );
-#if LIBAVFORMAT_VERSION_MAJOR > 52
- if ( self->video_format->iformat && self->video_format->iformat->priv_class && self->video_format->priv_data )
- apply_properties( self->video_format->priv_data, properties, AV_OPT_FLAG_DECODING_PARAM );
-#endif
self->audio_index = audio_index;
if ( self->video_format && video_index > -1 )
mlt_producer producer = self->parent;
int paused = 0;
- if ( position != self->video_expected || self->last_position < 0 )
+ if ( self->seekable && ( position != self->video_expected || self->last_position < 0 ) )
{
mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );
while( ret >= 0 && !got_picture )
{
// Read a packet
- ret = av_read_frame( context, &pkt );
+ pthread_mutex_lock( &self->packets_mutex );
+ if ( mlt_deque_count( self->vpackets ) )
+ {
+ AVPacket *tmp = (AVPacket*) mlt_deque_pop_front( self->vpackets );
+ pkt = *tmp;
+ free( tmp );
+ }
+ else
+ {
+ ret = av_read_frame( context, &pkt );
+ if ( ret >= 0 && !self->seekable && pkt.stream_index == self->audio_index )
+ {
+ if ( !av_dup_packet( &pkt ) )
+ {
+ AVPacket *tmp = malloc( sizeof(AVPacket) );
+ *tmp = pkt;
+ mlt_deque_push_back( self->apackets, tmp );
+ }
+ }
+ }
+ pthread_mutex_unlock( &self->packets_mutex );
// We only deal with video from the selected video_index
if ( ret >= 0 && pkt.stream_index == self->video_index && pkt.size > 0 )
got_picture = 0;
}
}
- if ( ret >= 0 )
+ if ( self->seekable || pkt.stream_index != self->audio_index )
av_free_packet( &pkt );
}
}
// Reopen the file if necessary
if ( !context && index > -1 )
{
- mlt_events_block( properties, producer );
producer_open( self, mlt_service_profile( MLT_PRODUCER_SERVICE(producer) ),
mlt_properties_get( properties, "resource" ) );
context = self->video_format;
- if ( self->dummy_context )
- {
- av_close_input_file( self->dummy_context );
- self->dummy_context = NULL;
- }
- mlt_events_unblock( properties, producer );
- if ( self->audio_format && !self->audio_streams )
- get_audio_streams_info( self );
-
- // Process properties as AVOptions
- if ( context )
- {
- apply_properties( context, properties, AV_OPT_FLAG_DECODING_PARAM );
-#if LIBAVFORMAT_VERSION_MAJOR > 52
- if ( context->iformat && context->iformat->priv_class && context->priv_data )
- apply_properties( context->priv_data, properties, AV_OPT_FLAG_DECODING_PARAM );
-#endif
- }
}
// Exception handling for video_index
int paused = 0;
// Seek if necessary
- if ( position != self->audio_expected )
+ if ( self->seekable && position != self->audio_expected )
{
if ( position + 1 == self->audio_expected )
{
}
// Read a packet
- ret = av_read_frame( context, &pkt );
+ pthread_mutex_lock( &self->packets_mutex );
+ if ( mlt_deque_count( self->apackets ) )
+ {
+ AVPacket *tmp = (AVPacket*) mlt_deque_pop_front( self->apackets );
+ pkt = *tmp;
+ free( tmp );
+ }
+ else
+ {
+ ret = av_read_frame( context, &pkt );
+ if ( ret >= 0 && !self->seekable && pkt.stream_index == self->video_index )
+ {
+ if ( !av_dup_packet( &pkt ) )
+ {
+ AVPacket *tmp = malloc( sizeof(AVPacket) );
+ *tmp = pkt;
+ mlt_deque_push_back( self->vpackets, tmp );
+ }
+ }
+ }
+ pthread_mutex_unlock( &self->packets_mutex );
// We only deal with audio from the selected audio index
index = pkt.stream_index;
self->audio_codec[index]->channels : *channels;
ret = decode_audio( self, &ignore, pkt, channels2, *samples, real_timecode, fps );
}
- av_free_packet( &pkt );
+
+ if ( self->seekable || index != self->video_index )
+ av_free_packet( &pkt );
if ( self->audio_index == INT_MAX && ret >= 0 )
{
// Reopen the file if necessary
if ( !context && self->audio_index > -1 && index > -1 )
{
- mlt_events_block( properties, producer );
producer_open( self, mlt_service_profile( MLT_PRODUCER_SERVICE(producer) ),
mlt_properties_get( properties, "resource" ) );
context = self->audio_format;
- if ( self->dummy_context )
- {
- av_close_input_file( self->dummy_context );
- self->dummy_context = NULL;
- }
- mlt_events_unblock( properties, producer );
- if ( self->audio_format )
- get_audio_streams_info( self );
}
// Exception handling for audio_index
static void producer_avformat_close( producer_avformat self )
{
mlt_log_debug( NULL, "producer_avformat_close\n" );
- // Close the file
+
+ // Cleanup av contexts
av_free( self->av_frame );
avformat_lock();
int i;
}
if ( self->video_codec )
avcodec_close( self->video_codec );
+ // Close the file
if ( self->dummy_context )
av_close_input_file( self->dummy_context );
- if ( self->audio_format )
+ if ( self->seekable && self->audio_format )
av_close_input_file( self->audio_format );
if ( self->video_format )
av_close_input_file( self->video_format );
#endif
if ( self->image_cache )
mlt_cache_close( self->image_cache );
+
+ // Cleanup the mutexes
pthread_mutex_destroy( &self->audio_mutex );
pthread_mutex_destroy( &self->video_mutex );
+ pthread_mutex_destroy( &self->packets_mutex );
+
+ // Cleanup the packet queues
+ AVPacket *pkt;
+ while ( ( pkt = mlt_deque_pop_back( self->apackets ) ) )
+ {
+ av_free_packet( pkt );
+ free( pkt );
+ }
+ while ( ( pkt = mlt_deque_pop_back( self->vpackets ) ) )
+ {
+ av_free_packet( pkt );
+ free( pkt );
+ }
+
free( self );
}