Skip to content

Commit

Permalink
V4L/DVB (5973): ivtv: attach yuv field order to each frame
Browse files Browse the repository at this point in the history
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 <ian@iarmst.demon.co.uk>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
  • Loading branch information
Ian Armstrong authored and Mauro Carvalho Chehab committed Oct 10, 2007
1 parent 943e891 commit bfd7bea
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 10 deletions.
7 changes: 6 additions & 1 deletion drivers/media/video/ivtv/ivtv-driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -603,7 +604,6 @@ struct yuv_playback_info
int decode_height;

int frame_interlaced;
int frame_interlaced_last;

int lace_mode;
int lace_threshold;
Expand All @@ -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;
Expand Down
22 changes: 14 additions & 8 deletions drivers/media/video/ivtv/ivtv-irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down Expand Up @@ -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 ++;
}
}

Expand Down
12 changes: 11 additions & 1 deletion drivers/media/video/ivtv/ivtv-yuv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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]))) {
Expand All @@ -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);

Expand Down

0 comments on commit bfd7bea

Please sign in to comment.