diff options
-rw-r--r-- | drivers/media/video/ivtv/ivtv-driver.h | 7 | ||||
-rw-r--r-- | drivers/media/video/ivtv/ivtv-irq.c | 22 | ||||
-rw-r--r-- | drivers/media/video/ivtv/ivtv-yuv.c | 12 |
3 files changed, 31 insertions, 10 deletions
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 6e53a1f04f7e..6c7c9a57a1ab 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -531,6 +531,7 @@ struct yuv_frame_info u32 tru_w; u32 tru_h; u32 offset_y; + int lace_mode; }; #define IVTV_YUV_MODE_INTERLACED 0x00 @@ -603,7 +604,6 @@ struct yuv_playback_info int decode_height; int frame_interlaced; - int frame_interlaced_last; int lace_mode; int lace_threshold; @@ -614,6 +614,11 @@ struct yuv_playback_info u32 yuv_forced_update; int update_frame; + + int sync_field[4]; /* Field to sync on */ + int field_delay[4]; /* Flag to extend duration of previous frame */ + u8 fields_lapsed; /* Counter used when delaying a frame */ + struct yuv_frame_info new_frame_info[4]; struct yuv_frame_info old_frame_info; struct yuv_frame_info old_frame_info_args; diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index fcd6e7f5f121..88c6f4ff5c6d 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -698,17 +698,21 @@ static void ivtv_irq_vsync(struct ivtv *itv) if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n"); - if (((frame ^ itv->yuv_info.lace_sync_field) == 0 && ((itv->lastVsyncFrame & 1) ^ itv->yuv_info.lace_sync_field)) || + if (((frame ^ itv->yuv_info.sync_field[last_dma_frame]) == 0 && + ((itv->lastVsyncFrame & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) || (frame != (itv->lastVsyncFrame & 1) && !itv->yuv_info.frame_interlaced)) { int next_dma_frame = last_dma_frame; - if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) { - write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c); - write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830); - write_reg(yuv_offset[next_dma_frame] >> 4, 0x834); - write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838); - next_dma_frame = (next_dma_frame + 1) & 0x3; - atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame); + if (!(itv->yuv_info.frame_interlaced && itv->yuv_info.field_delay[next_dma_frame] && itv->yuv_info.fields_lapsed < 1)) { + if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) { + write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c); + write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830); + write_reg(yuv_offset[next_dma_frame] >> 4, 0x834); + write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838); + next_dma_frame = (next_dma_frame + 1) & 0x3; + atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame); + itv->yuv_info.fields_lapsed = -1; + } } } if (frame != (itv->lastVsyncFrame & 1)) { @@ -749,6 +753,8 @@ static void ivtv_irq_vsync(struct ivtv *itv) set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); } } + + itv->yuv_info.fields_lapsed ++; } } diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index 5c94d3282c82..fa8c76f3d359 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -612,7 +612,6 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi itv->yuv_info.v_filter_2 = v_filter_2; } - itv->yuv_info.frame_interlaced_last = itv->yuv_info.frame_interlaced; } /* Modify the supplied coordinate information to fit the visible osd area */ @@ -799,6 +798,7 @@ static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *windo (itv->yuv_info.old_frame_info.src_y != window->src_y) || (itv->yuv_info.old_frame_info.pan_y != window->pan_y) || (itv->yuv_info.old_frame_info.vis_h != window->vis_h) || + (itv->yuv_info.old_frame_info.lace_mode != window->lace_mode) || (itv->yuv_info.old_frame_info.interlaced_y != window->interlaced_y) || (itv->yuv_info.old_frame_info.interlaced_uv != window->interlaced_uv)) { yuv_update |= IVTV_YUV_UPDATE_VERTICAL; @@ -970,6 +970,9 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) itv->yuv_info.new_frame_info[frame].tru_w = args->src_width; itv->yuv_info.new_frame_info[frame].tru_h = args->src_height; + /* Snapshot field order */ + itv->yuv_info.sync_field[frame] = itv->yuv_info.lace_sync_field; + /* Are we going to offset the Y plane */ if (args->src.height + args->src.top < 512-16) itv->yuv_info.new_frame_info[frame].offset_y = 1; @@ -985,6 +988,7 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) itv->yuv_info.new_frame_info[frame].update = 0; itv->yuv_info.new_frame_info[frame].interlaced_y = 0; itv->yuv_info.new_frame_info[frame].interlaced_uv = 0; + itv->yuv_info.new_frame_info[frame].lace_mode = itv->yuv_info.lace_mode; if (memcmp (&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], sizeof (itv->yuv_info.new_frame_info[frame]))) { @@ -995,6 +999,12 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) itv->yuv_info.new_frame_info[frame].update |= register_update; + /* Should this frame be delayed ? */ + if (itv->yuv_info.sync_field[frame] != itv->yuv_info.sync_field[(frame - 1) & 3]) + itv->yuv_info.field_delay[frame] = 1; + else + itv->yuv_info.field_delay[frame] = 0; + /* DMA the frame */ mutex_lock(&itv->udma.lock); |