[PATCH][RFC] Run deinterlacer and decoder in separate threads
Petri Hintukainen <[email protected]> Tue, 15 May 2012 15:13:15 +0300
| Newsgroups | gmane.comp.video.xine.devel |
|---|---|
| Message-ID | <1337083995.29602.11.camel@ph-NF310> |
Hello, Attached patch runs deinterlacer (tvtime plugin) and video decoder in separate threads. It could be further improved by splitting deinterlacing to multiple threads, for example: - pipelining: color space conversion, pulldown detection, deinterlacing, chroma filter, ... - processing frames in slices Usage: xine --post tvtime:threads=1 Not deeply tested ... - Petri ------------------------------------------------------------------------------ Live Security Virtual Conference Exclusive live event will cover all the ways today's security and threat landscape has changed and how IT managers can respond. Discussions will include endpoint security, mobile security and the latest in malware threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/ _______________________________________________ xine-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/xine-devel
tvtime_thread.diff
(text/x-patch, 7.3 KB)
diff --git a/src/post/deinterlace/xine_plugin.c b/src/post/deinterlace/xine_plugin.c
--- a/src/post/deinterlace/xine_plugin.c
+++ b/src/post/deinterlace/xine_plugin.c
@@ -31,6 +31,8 @@
#define LOG
*/
+#define XINE_ENGINE_INTERNAL /* non-blocking ticket release */
+
#include <xine/xine_internal.h>
#include <xine/post.h>
#include <xine/xineutils.h>
@@ -79,6 +81,7 @@ typedef struct deinterlace_parameters_s
int use_progressive_frame_flag;
int chroma_filter;
int cheap_mode;
+ int threads;
} deinterlace_parameters_t;
@@ -104,6 +107,8 @@ PARAM_ITEM( POST_PARAM_TYPE_BOOL, chroma
"apply chroma filter after deinterlacing" )
PARAM_ITEM( POST_PARAM_TYPE_BOOL, cheap_mode, NULL, 0, 1, 0,
"skip image format conversion - cheaper but not 100% correct" )
+PARAM_ITEM( POST_PARAM_TYPE_INT, threads, NULL, 0, 1, 0,
+ "use multiple threads" )
END_PARAM_DESCR( param_descr )
@@ -136,6 +141,16 @@ struct post_plugin_deinterlace_s {
vo_frame_t *recent_frame[NUM_RECENT_FRAMES];
pthread_mutex_t lock;
+
+ uint8_t threads;
+ uint8_t thread_created;
+ pthread_t worker_thread;
+ pthread_mutex_t thread_lock;
+ pthread_cond_t thread_complete; /* thred can acceprt input, thread completed frame, thread finished */
+ pthread_cond_t thread_start; /* frame queued for thread */
+ vo_frame_t *thread_frame; /* incoming frame for worker thread */
+ xine_stream_t *thread_stream;
+ int thread_result; /* result of last draw */
};
@@ -144,10 +159,34 @@ typedef struct post_class_deinterlace_s
deinterlace_parameters_t init_param;
} post_class_deinterlace_t;
+static void deinterlace_thread_stop(post_plugin_deinterlace_t *this)
+{
+ if (this->thread_created) {
+
+ pthread_mutex_lock(&this->thread_lock);
+ this->thread_created = 0;
+ pthread_cond_signal(&this->thread_start);
+ pthread_mutex_unlock(&this->thread_lock);
+
+ pthread_join(this->worker_thread, NULL);
+
+ if (this->thread_frame) {
+ this->thread_frame->free(this->thread_frame);
+ this->thread_frame = NULL;
+ }
+
+ pthread_cond_destroy(&this->thread_complete);
+ pthread_cond_destroy(&this->thread_start);
+ pthread_mutex_destroy(&this->thread_lock);
+ }
+}
+
static void _flush_frames(post_plugin_deinterlace_t *this)
{
int i;
+ deinterlace_thread_stop(this);
+
for( i = 0; i < NUM_RECENT_FRAMES; i++ ) {
if( this->recent_frame[i] ) {
this->recent_frame[i]->free(this->recent_frame[i]);
@@ -178,6 +217,7 @@ static int set_parameters (xine_post_t *
this->use_progressive_frame_flag = param->use_progressive_frame_flag;
this->chroma_filter = param->chroma_filter;
this->cheap_mode = param->cheap_mode;
+ this->threads = param->threads;
this->tvtime_changed++;
@@ -199,6 +239,7 @@ static int get_parameters (xine_post_t *
param->use_progressive_frame_flag = this->use_progressive_frame_flag;
param->chroma_filter = this->chroma_filter;
param->cheap_mode = this->cheap_mode;
+ param->threads = this->threads;
return 1;
}
@@ -258,6 +299,8 @@ static char * get_static_help (void) {
"systems to try deinterlace algorithms, in a tradeoff between quality "
"and cpu usage.\n"
"\n"
+ " Threads: run decoder and deinterlacer in sepatate threads\n"
+ "\n"
"* Uses several algorithms from tvtime and dscaler projects.\n"
"Deinterlacing methods: (Not all methods are available for all platforms)\n"
"\n"
@@ -366,6 +409,7 @@ static void *deinterlace_init_plugin(xin
class->init_param.use_progressive_frame_flag = 1;
class->init_param.chroma_filter = 0;
class->init_param.cheap_mode = 0;
+ class->init_param.threads = 0;
return &class->class;
}
@@ -435,6 +479,7 @@ static void deinterlace_dispose(post_plu
post_plugin_deinterlace_t *this = (post_plugin_deinterlace_t *)this_gen;
if (_x_post_dispose(this_gen)) {
+ deinterlace_thread_stop(this);
_flush_frames(this);
pthread_mutex_destroy(&this->lock);
free(this->tvtime);
@@ -681,7 +738,8 @@ static int deinterlace_build_output_fiel
return skip;
}
-static int deinterlace_draw(vo_frame_t *frame, xine_stream_t *stream)
+
+static int deinterlace_draw_int(vo_frame_t *frame, xine_stream_t *stream)
{
post_video_port_t *port = (post_video_port_t *)frame->port;
post_plugin_deinterlace_t *this = (post_plugin_deinterlace_t *)port->post;
@@ -924,3 +982,103 @@ static int deinterlace_draw(vo_frame_t *
return skip;
}
+
+static void *deinterlace_thread(void *p)
+{
+ post_plugin_deinterlace_t *this = p;
+ xine_stream_t *stream;
+ vo_frame_t *frame;
+ int result;
+
+ pthread_mutex_lock(&this->thread_lock);
+
+ while (this->thread_created) {
+
+ if (!this->thread_frame) {
+ pthread_cond_wait(&this->thread_start, &this->thread_lock);
+ }
+
+ if (this->thread_frame) {
+ /* got frame */
+ stream = this->thread_stream;
+ frame = this->thread_frame;
+ this->thread_frame = NULL;
+
+ /* next frame can be queued now */
+ pthread_cond_signal(&this->thread_complete); /* free queue slot */
+ pthread_mutex_unlock(&this->thread_lock);
+
+ /* deinterlace */
+
+ //_x_post_lock(&this->post);
+ this->post.running_ticket->acquire(this->post.running_ticket, 1);
+
+ result = deinterlace_draw_int(frame, stream);
+ frame->free(frame);
+
+ //_x_post_unlock(&this->post);
+ this->post.running_ticket->release_nonblocking(this->post.running_ticket, 1);
+ //_x_post_rewire(post);
+
+ /* store result */
+ pthread_mutex_lock(&this->thread_lock);
+ this->thread_result = result;
+ pthread_cond_signal(&this->thread_complete); /* frame complete */
+ }
+ }
+
+ pthread_cond_signal(&this->thread_complete); /* thread finished */
+ pthread_mutex_unlock(&this->thread_lock);
+
+ return NULL;
+}
+
+static void deinterlace_thread_start(post_plugin_deinterlace_t *this)
+{
+ if (this->threads && !this->thread_created) {
+ pthread_mutex_init(&this->thread_lock, NULL);
+ pthread_cond_init(&this->thread_complete, NULL);
+ pthread_cond_init(&this->thread_start, NULL);
+
+ pthread_mutex_lock(&this->thread_lock);
+ pthread_create(&this->worker_thread, NULL, deinterlace_thread, this);
+ this->thread_created = 1;
+ this->thread_result = 0;
+ pthread_mutex_unlock(&this->thread_lock);
+ }
+}
+
+static int deinterlace_draw(vo_frame_t *frame, xine_stream_t *stream)
+{
+ post_video_port_t *port = (post_video_port_t *)frame->port;
+ post_plugin_deinterlace_t *this = (post_plugin_deinterlace_t *)port->post;
+
+ if (this->threads) {
+ int result = 0;
+
+ deinterlace_thread_start(this);
+
+ pthread_mutex_lock(&this->thread_lock);
+
+ while (this->thread_frame && this->threads) {
+ pthread_cond_wait(&this->thread_complete, &this->thread_lock);
+ }
+
+ if (this->threads) {
+ result = this->thread_result;
+ this->thread_stream = stream;
+ this->thread_frame = frame;
+ frame->lock(frame);
+ pthread_cond_signal(&this->thread_start);
+
+ pthread_mutex_unlock(&this->thread_lock);
+ return result;
+ }
+
+ pthread_mutex_unlock(&this->thread_lock);
+ }
+
+ deinterlace_thread_stop(this);
+
+ return deinterlace_draw_int(frame, stream);
+}