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
{
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();
// Lock the service
pthread_mutex_init( &self->audio_mutex, NULL );
pthread_mutex_init( &self->video_mutex, NULL );
+ pthread_mutex_init( &self->packets_mutex, NULL );
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;
// 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 );
+ av_find_stream_info( self->audio_format );
+ }
+ else
+ {
+ self->audio_format = self->video_format;
+ }
}
else if ( self->audio_index != -1 )
{
}
if ( filename )
free( filename );
+ if ( !error )
+ {
+ self->apackets = mlt_deque_init();
+ self->vpackets = mlt_deque_init();
+ }
// Unlock the service
pthread_mutex_unlock( &self->audio_mutex );
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 );
}
}
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 )
{
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 );
}