Commit 5614b021 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

V4L/DVB (6095): ivtv: fix VIDIOC_G_ENC_INDEX flag handling

Due to a documentation bug (the type mask is 3 bits long, not 2) the wrong
frame types were filled in: the B and P frame types were swapped.

This bug also hid a second bug: when a capture is stopped a last entry is
written into the pgm index buffer with internal type 0, denoting the end
of the program. This entry wasn't ignored, instead it was accidentally
returned to the caller as a P frame.
Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent 19299b1a
...@@ -407,8 +407,10 @@ Description ...@@ -407,8 +407,10 @@ Description
u32 length; // Length of this frame u32 length; // Length of this frame
u32 offset_low; // Offset in the file of the u32 offset_low; // Offset in the file of the
u32 offset_high; // start of this frame u32 offset_high; // start of this frame
u32 mask1; // Bits 0-1 are the type mask: u32 mask1; // Bits 0-2 are the type mask:
// 1=I, 2=P, 4=B // 1=I, 2=P, 4=B
// 0=End of Program Index, other fields
// are invalid.
u32 pts; // The PTS of the frame u32 pts; // The PTS of the frame
u32 mask2; // Bit 0 is bit 32 of the pts. u32 mask2; // Bit 0 is bit 32 of the pts.
}; };
......
...@@ -190,7 +190,9 @@ static void ivtv_update_pgm_info(struct ivtv *itv) ...@@ -190,7 +190,9 @@ static void ivtv_update_pgm_info(struct ivtv *itv)
int idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num; int idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num;
struct v4l2_enc_idx_entry *e = itv->pgm_info + idx; struct v4l2_enc_idx_entry *e = itv->pgm_info + idx;
u32 addr = itv->pgm_info_offset + 4 + idx * 24; u32 addr = itv->pgm_info_offset + 4 + idx * 24;
const int mapping[] = { V4L2_ENC_IDX_FRAME_P, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_B, 0 }; const int mapping[8] = { -1, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_P, -1,
V4L2_ENC_IDX_FRAME_B, -1, -1, -1 };
// 1=I, 2=P, 4=B
e->offset = read_enc(addr + 4) + ((u64)read_enc(addr + 8) << 32); e->offset = read_enc(addr + 4) + ((u64)read_enc(addr + 8) << 32);
if (e->offset > itv->mpg_data_received) { if (e->offset > itv->mpg_data_received) {
...@@ -199,7 +201,7 @@ static void ivtv_update_pgm_info(struct ivtv *itv) ...@@ -199,7 +201,7 @@ static void ivtv_update_pgm_info(struct ivtv *itv)
e->offset += itv->vbi_data_inserted; e->offset += itv->vbi_data_inserted;
e->length = read_enc(addr); e->length = read_enc(addr);
e->pts = read_enc(addr + 16) + ((u64)(read_enc(addr + 20) & 1) << 32); e->pts = read_enc(addr + 16) + ((u64)(read_enc(addr + 20) & 1) << 32);
e->flags = mapping[read_enc(addr + 12) & 3]; e->flags = mapping[read_enc(addr + 12) & 7];
i++; i++;
} }
itv->pgm_info_write_idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num; itv->pgm_info_write_idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num;
......
...@@ -1099,14 +1099,21 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void ...@@ -1099,14 +1099,21 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
case VIDIOC_G_ENC_INDEX: { case VIDIOC_G_ENC_INDEX: {
struct v4l2_enc_idx *idx = arg; struct v4l2_enc_idx *idx = arg;
struct v4l2_enc_idx_entry *e = idx->entry;
int entries;
int i; int i;
idx->entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) % entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) %
IVTV_MAX_PGM_INDEX; IVTV_MAX_PGM_INDEX;
if (idx->entries > V4L2_ENC_IDX_ENTRIES) if (entries > V4L2_ENC_IDX_ENTRIES)
idx->entries = V4L2_ENC_IDX_ENTRIES; entries = V4L2_ENC_IDX_ENTRIES;
for (i = 0; i < idx->entries; i++) { idx->entries = 0;
idx->entry[i] = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX]; for (i = 0; i < entries; i++) {
*e = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX];
if ((e->flags & V4L2_ENC_IDX_FRAME_MASK) <= V4L2_ENC_IDX_FRAME_B) {
idx->entries++;
e++;
}
} }
itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX; itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX;
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment