From: Dan Dennedy Date: Sat, 19 Nov 2011 22:31:17 +0000 (-0800) Subject: add caching to decklink producer X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=f6cdf05c4fb209f0d58c64d5e3b38d9b1138ade9;p=mlt add caching to decklink producer Now it supports YADIF deinterlace and framerate conversion. --- diff --git a/src/modules/decklink/producer_decklink.cpp b/src/modules/decklink/producer_decklink.cpp index 5eadc1c7..a857ac4d 100644 --- a/src/modules/decklink/producer_decklink.cpp +++ b/src/modules/decklink/producer_decklink.cpp @@ -47,6 +47,7 @@ private: int m_topFieldFirst; int m_colorspace; int m_vancLines; + mlt_cache m_cache; BMDDisplayMode getDisplayMode( mlt_profile profile, int vancLines ) { @@ -89,17 +90,18 @@ public: ~DeckLinkProducer() { - if ( m_decklinkInput ) - m_decklinkInput->Release(); - if ( m_decklink ) - m_decklink->Release(); if ( m_queue ) { stop(); mlt_deque_close( m_queue ); pthread_mutex_destroy( &m_mutex ); pthread_cond_destroy( &m_condition ); + mlt_cache_close( m_cache ); } + if ( m_decklinkInput ) + m_decklinkInput->Release(); + if ( m_decklink ) + m_decklink->Release(); } bool open( unsigned card = 0 ) @@ -142,6 +144,10 @@ public: m_started = false; m_dropped = 0; m_isBuffering = true; + m_cache = mlt_cache_init(); + + // 3 covers YADIF and increasing framerate use cases + mlt_cache_set_size( m_cache, 3 ); } catch ( const char *error ) { @@ -240,12 +246,33 @@ public: pthread_mutex_unlock( &m_mutex ); } + mlt_frame cloneFrame( mlt_frame frame ) + { + mlt_frame new_frame = mlt_frame_init( NULL ); + mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); + mlt_properties new_props = MLT_FRAME_PROPERTIES( new_frame ); + void *data; + void *copy; + int size; + + mlt_properties_inherit( new_props, properties ); + mlt_properties_set_int( new_props, "audio_samples", 0 ); + data = mlt_properties_get_data( properties, "image", &size ); + copy = mlt_pool_alloc( size ); + memcpy( copy, data, size ); + mlt_properties_set_data( new_props, "image", copy, size, mlt_pool_release, NULL ); + + return new_frame; + } + mlt_frame getFrame() { mlt_frame frame = NULL; struct timeval now; struct timespec tm; double fps = mlt_producer_get_fps( getProducer() ); + mlt_position position = mlt_producer_position( getProducer() ); + mlt_cache_item cached = mlt_cache_get( m_cache, (void*) position ); // Allow the buffer to fill to the requested initial buffer level. if ( m_isBuffering ) @@ -270,24 +297,36 @@ public: pthread_mutex_unlock( &m_mutex ); } - // Wait if queue is empty - pthread_mutex_lock( &m_mutex ); - while ( mlt_deque_count( m_queue ) < 1 ) + if ( cached ) { - // Wait up to twice frame duration - gettimeofday( &now, NULL ); - long usec = now.tv_sec * 1000000 + now.tv_usec; - usec += 2000000 / fps; - tm.tv_sec = usec / 1000000; - tm.tv_nsec = (usec % 1000000) * 1000; - if ( pthread_cond_timedwait( &m_condition, &m_mutex, &tm ) ) - // Stop waiting if error (timed out) - break; + // Copy cached frame instead of pulling from queue + frame = cloneFrame( (mlt_frame) mlt_cache_item_data( cached, NULL ) ); + mlt_cache_item_close( cached ); } + else + { + // Wait if queue is empty + pthread_mutex_lock( &m_mutex ); + while ( mlt_deque_count( m_queue ) < 1 ) + { + // Wait up to twice frame duration + gettimeofday( &now, NULL ); + long usec = now.tv_sec * 1000000 + now.tv_usec; + usec += 2000000 / fps; + tm.tv_sec = usec / 1000000; + tm.tv_nsec = (usec % 1000000) * 1000; + if ( pthread_cond_timedwait( &m_condition, &m_mutex, &tm ) ) + // Stop waiting if error (timed out) + break; + } + frame = ( mlt_frame ) mlt_deque_pop_front( m_queue ); + pthread_mutex_unlock( &m_mutex ); - // Get the first frame from the queue - frame = ( mlt_frame ) mlt_deque_pop_front( m_queue ); - pthread_mutex_unlock( &m_mutex ); + // add to cache + if ( frame ) + mlt_cache_put( m_cache, (void*) position, cloneFrame( frame ), 0, + (mlt_destructor) mlt_frame_close ); + } // Set frame timestamp and properties if ( frame ) @@ -315,6 +354,9 @@ public: mlt_properties_set_int( properties, "audio_channels", mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" ) ); } + else + mlt_log_warning( getProducer(), "buffer underrun\n" ); + return frame; }