diff options
author | Mike Isely <isely@pobox.com> | 2010-02-06 02:10:38 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-02-26 15:11:05 -0300 |
commit | 6e9313755aacdb9fd4eec58cbd9653212e2e2cdc (patch) | |
tree | cb43fe2414bf378c483d36aab3256a8f7472e20c /drivers/media | |
parent | 7cae112ebe10e186c3bdae1f20865941717e37a2 (diff) |
V4L/DVB: pvrusb2: Enforce a 300msec stabilization interval during stream strart
Martin Dauskardt <martin.dauskardt@gmx.de> has determined that the
encoder has a much better chance of starting cleanly if we
deliberately hold off starting it util the video digitizer has had a
chance to run for at least 300msec first. These changes implement an
enforced 300msec wait in the state machine that orchestrates streaming
start / stop.
Signed-off-by: Mike Isely <isely@pobox.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h | 12 | ||||
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-hdw.c | 41 | ||||
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-hdw.h | 1 |
3 files changed, 49 insertions, 5 deletions
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h index de5485f506b1..cb4057bb07a0 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h @@ -233,8 +233,9 @@ struct pvr2_hdw { int state_encoder_waitok; /* Encoder pre-wait done */ int state_encoder_runok; /* Encoder has run for >= .25 sec */ int state_decoder_run; /* Decoder is running */ + int state_decoder_ready; /* Decoder is stabilized & streamable */ int state_usbstream_run; /* FX2 is streaming */ - int state_decoder_quiescent; /* Decoder idle for > 50msec */ + int state_decoder_quiescent; /* Decoder idle for minimal interval */ int state_pipeline_config; /* Pipeline is configured */ int state_pipeline_req; /* Somebody wants to stream */ int state_pipeline_pause; /* Pipeline must be paused */ @@ -255,9 +256,16 @@ struct pvr2_hdw { void (*state_func)(void *); void *state_data; - /* Timer for measuring decoder settling time */ + /* Timer for measuring required decoder settling time before we're + allowed to fire it up again. */ struct timer_list quiescent_timer; + /* Timer for measuring decoder stabilization time, which is the + amount of time we need to let the decoder run before we can + trust its output (otherwise the encoder might see garbage and + then fail to start correctly). */ + struct timer_list decoder_stabilization_timer; + /* Timer for measuring encoder pre-wait time */ struct timer_list encoder_wait_timer; diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index ad9ed51f7b9d..79b2a544ccba 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -48,6 +48,10 @@ before we are allowed to start it running. */ #define TIME_MSEC_DECODER_WAIT 50 +/* This defines a minimum interval that the decoder must be allowed to run + before we can safely begin using its streaming output. */ +#define TIME_MSEC_DECODER_STABILIZATION_WAIT 300 + /* This defines a minimum interval that the encoder must remain quiet before we are allowed to configure it. I had this originally set to 50msec, but Martin Dauskardt <martin.dauskardt@gmx.de> reports that @@ -334,6 +338,7 @@ static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw); static void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw); static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw); static void pvr2_hdw_quiescent_timeout(unsigned long); +static void pvr2_hdw_decoder_stabilization_timeout(unsigned long); static void pvr2_hdw_encoder_wait_timeout(unsigned long); static void pvr2_hdw_encoder_run_timeout(unsigned long); static int pvr2_issue_simple_cmd(struct pvr2_hdw *,u32); @@ -2462,6 +2467,11 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, hdw->quiescent_timer.data = (unsigned long)hdw; hdw->quiescent_timer.function = pvr2_hdw_quiescent_timeout; + init_timer(&hdw->decoder_stabilization_timer); + hdw->decoder_stabilization_timer.data = (unsigned long)hdw; + hdw->decoder_stabilization_timer.function = + pvr2_hdw_decoder_stabilization_timeout; + init_timer(&hdw->encoder_wait_timer); hdw->encoder_wait_timer.data = (unsigned long)hdw; hdw->encoder_wait_timer.function = pvr2_hdw_encoder_wait_timeout; @@ -2675,6 +2685,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, fail: if (hdw) { del_timer_sync(&hdw->quiescent_timer); + del_timer_sync(&hdw->decoder_stabilization_timer); del_timer_sync(&hdw->encoder_run_timer); del_timer_sync(&hdw->encoder_wait_timer); if (hdw->workqueue) { @@ -2742,6 +2753,7 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw) hdw->workqueue = NULL; } del_timer_sync(&hdw->quiescent_timer); + del_timer_sync(&hdw->decoder_stabilization_timer); del_timer_sync(&hdw->encoder_run_timer); del_timer_sync(&hdw->encoder_wait_timer); if (hdw->fw_buffer) { @@ -4453,7 +4465,7 @@ static int state_check_enable_encoder_run(struct pvr2_hdw *hdw) switch (hdw->pathway_state) { case PVR2_PATHWAY_ANALOG: - if (hdw->state_decoder_run) { + if (hdw->state_decoder_run && hdw->state_decoder_ready) { /* In analog mode, if the decoder is running, then run the encoder. */ return !0; @@ -4520,6 +4532,17 @@ static void pvr2_hdw_quiescent_timeout(unsigned long data) } +/* Timeout function for decoder stabilization timer. */ +static void pvr2_hdw_decoder_stabilization_timeout(unsigned long data) +{ + struct pvr2_hdw *hdw = (struct pvr2_hdw *)data; + hdw->state_decoder_ready = !0; + trace_stbit("state_decoder_ready", hdw->state_decoder_ready); + hdw->state_stale = !0; + queue_work(hdw->workqueue, &hdw->workpoll); +} + + /* Timeout function for encoder wait timer. */ static void pvr2_hdw_encoder_wait_timeout(unsigned long data) { @@ -4558,8 +4581,13 @@ static int state_eval_decoder_run(struct pvr2_hdw *hdw) } hdw->state_decoder_quiescent = 0; hdw->state_decoder_run = 0; - /* paranoia - solve race if timer just completed */ + /* paranoia - solve race if timer(s) just completed */ del_timer_sync(&hdw->quiescent_timer); + /* Kill the stabilization timer, in case we're killing the + encoder before the previous stabilization interval has + been properly timed. */ + del_timer_sync(&hdw->decoder_stabilization_timer); + hdw->state_decoder_ready = 0; } else { if (!hdw->state_decoder_quiescent) { if (!timer_pending(&hdw->quiescent_timer)) { @@ -4597,10 +4625,16 @@ static int state_eval_decoder_run(struct pvr2_hdw *hdw) if (hdw->flag_decoder_missed) return 0; if (pvr2_decoder_enable(hdw,!0) < 0) return 0; hdw->state_decoder_quiescent = 0; + hdw->state_decoder_ready = 0; hdw->state_decoder_run = !0; + hdw->decoder_stabilization_timer.expires = + jiffies + + (HZ * TIME_MSEC_DECODER_STABILIZATION_WAIT / 1000); + add_timer(&hdw->decoder_stabilization_timer); } trace_stbit("state_decoder_quiescent",hdw->state_decoder_quiescent); trace_stbit("state_decoder_run",hdw->state_decoder_run); + trace_stbit("state_decoder_ready", hdw->state_decoder_ready); return !0; } @@ -4798,7 +4832,8 @@ static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which, buf,acnt, "worker:%s%s%s%s%s%s%s", (hdw->state_decoder_run ? - " <decode:run>" : + (hdw->state_decoder_ready ? + "<decode:run>" : " <decode:start>") : (hdw->state_decoder_quiescent ? "" : " <decode:stop>")), (hdw->state_decoder_quiescent ? diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h index 56e70eae20c1..51d3009ab57f 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h @@ -306,6 +306,7 @@ struct pvr2_hdw_debug_info { int state_encoder_ok; int state_encoder_run; int state_decoder_run; + int state_decoder_ready; int state_usbstream_run; int state_decoder_quiescent; int state_pipeline_config; |