Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=bfd7beacff2b5c811badb587a74c3dfbf7f98721
Commit:     bfd7beacff2b5c811badb587a74c3dfbf7f98721
Parent:     943e8910db31e36d945f2bf7d4c273ca5fa01f6e
Author:     Ian Armstrong <[EMAIL PROTECTED]>
AuthorDate: Fri Aug 3 10:01:39 2007 -0300
Committer:  Mauro Carvalho Chehab <[EMAIL PROTECTED]>
CommitDate: Tue Oct 9 22:04:29 2007 -0300

    V4L/DVB (5973): ivtv: attach yuv field order to each frame
    
    In the current driver, the field order is global. As soon as it's changed it
    takes immediate effect. This is a problem when the video changes order mid
    stream. Although it mostly works okay, the video may judder / flicker.
    
    This patch attaches the field order to the frame, so that any buffered 
frames
    will not be displayed until the correct field. In the event that the field
    order is changed mid stream, the driver will ensure that the previous frame
    is displayed for a minimum of 3 fields. These are the two original fields 
the
    frame should have occupied, plus the one extra since the new frame still has
    to wait for the correct field.
    
    Signed-off-by: Ian Armstrong <[EMAIL PROTECTED]>
    Signed-off-by: Hans Verkuil <[EMAIL PROTECTED]>
    Signed-off-by: Mauro Carvalho Chehab <[EMAIL PROTECTED]>
---
 drivers/media/video/ivtv/ivtv-driver.h |    7 ++++++-
 drivers/media/video/ivtv/ivtv-irq.c    |   22 ++++++++++++++--------
 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 6e53a1f..6c7c9a5 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 fcd6e7f..88c6f4f 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 5c94d32..fa8c76f 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);
 
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to