V4L/DVB: gspca - main: Simplify image building

The image pointer and its length are now in the main structure instead
of in the frame buffer. They are updated on application vidioc_qbuf and
in the URB interrupt function when ending an image.

Signed-off-by: Jean-François Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
Jean-François Moine 2010-06-27 03:08:19 -03:00 committed by Mauro Carvalho Chehab
parent c6dc725c8e
commit b192ca9837
10 changed files with 79 additions and 98 deletions

View file

@ -1760,22 +1760,23 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
data[25] == sd->params.roi.colEnd && data[25] == sd->params.roi.colEnd &&
data[26] == sd->params.roi.rowStart && data[26] == sd->params.roi.rowStart &&
data[27] == sd->params.roi.rowEnd) { data[27] == sd->params.roi.rowEnd) {
struct gspca_frame *frame = gspca_get_i_frame(gspca_dev); u8 *image;
atomic_set(&sd->cam_exposure, data[39] * 2); atomic_set(&sd->cam_exposure, data[39] * 2);
atomic_set(&sd->fps, data[41]); atomic_set(&sd->fps, data[41]);
if (frame == NULL) { image = gspca_dev->image;
if (image == NULL) {
gspca_dev->last_packet_type = DISCARD_PACKET; gspca_dev->last_packet_type = DISCARD_PACKET;
return; return;
} }
/* Check for proper EOF for last frame */ /* Check for proper EOF for last frame */
if ((frame->data_end - frame->data) > 4 && if (gspca_dev->image_len > 4 &&
frame->data_end[-4] == 0xff && image[gspca_dev->image_len - 4] == 0xff &&
frame->data_end[-3] == 0xff && image[gspca_dev->image_len - 3] == 0xff &&
frame->data_end[-2] == 0xff && image[gspca_dev->image_len - 2] == 0xff &&
frame->data_end[-1] == 0xff) image[gspca_dev->image_len - 1] == 0xff)
gspca_frame_add(gspca_dev, LAST_PACKET, gspca_frame_add(gspca_dev, LAST_PACKET,
NULL, 0); NULL, 0);

View file

@ -294,19 +294,6 @@ static inline int gspca_input_connect(struct gspca_dev *dev)
} }
#endif #endif
/* get the current input frame buffer */
struct gspca_frame *gspca_get_i_frame(struct gspca_dev *gspca_dev)
{
struct gspca_frame *frame;
frame = gspca_dev->cur_frame;
if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS)
!= V4L2_BUF_FLAG_QUEUED)
return NULL;
return frame;
}
EXPORT_SYMBOL(gspca_get_i_frame);
/* /*
* fill a video frame from an URB and resubmit * fill a video frame from an URB and resubmit
*/ */
@ -328,6 +315,8 @@ static void fill_frame(struct gspca_dev *gspca_dev,
urb->status = 0; urb->status = 0;
goto resubmit; goto resubmit;
} }
if (gspca_dev->image == NULL)
gspca_dev->last_packet_type = DISCARD_PACKET;
pkt_scan = gspca_dev->sd_desc->pkt_scan; pkt_scan = gspca_dev->sd_desc->pkt_scan;
for (i = 0; i < urb->number_of_packets; i++) { for (i = 0; i < urb->number_of_packets; i++) {
@ -440,19 +429,16 @@ void gspca_frame_add(struct gspca_dev *gspca_dev,
PDEBUG(D_PACK, "add t:%d l:%d", packet_type, len); PDEBUG(D_PACK, "add t:%d l:%d", packet_type, len);
/* check the availability of the frame buffer */ /* check the availability of the frame buffer */
frame = gspca_dev->cur_frame; if (gspca_dev->image == NULL)
if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS)
!= V4L2_BUF_FLAG_QUEUED) {
gspca_dev->last_packet_type = DISCARD_PACKET;
return; return;
}
/* when start of a new frame, if the current frame buffer
* is not queued, discard the whole frame */
if (packet_type == FIRST_PACKET) { if (packet_type == FIRST_PACKET) {
frame->data_end = frame->data; i = gspca_dev->fr_i;
j = gspca_dev->fr_queue[i];
frame = &gspca_dev->frame[j];
frame->v4l2_buf.timestamp = ktime_to_timeval(ktime_get()); frame->v4l2_buf.timestamp = ktime_to_timeval(ktime_get());
frame->v4l2_buf.sequence = ++gspca_dev->sequence; frame->v4l2_buf.sequence = ++gspca_dev->sequence;
gspca_dev->image_len = 0;
} else if (gspca_dev->last_packet_type == DISCARD_PACKET) { } else if (gspca_dev->last_packet_type == DISCARD_PACKET) {
if (packet_type == LAST_PACKET) if (packet_type == LAST_PACKET)
gspca_dev->last_packet_type = packet_type; gspca_dev->last_packet_type = packet_type;
@ -461,26 +447,29 @@ void gspca_frame_add(struct gspca_dev *gspca_dev,
/* append the packet to the frame buffer */ /* append the packet to the frame buffer */
if (len > 0) { if (len > 0) {
if (frame->data_end - frame->data + len if (gspca_dev->image_len + len > gspca_dev->frsz) {
> frame->v4l2_buf.length) { PDEBUG(D_ERR|D_PACK, "frame overflow %d > %d",
PDEBUG(D_ERR|D_PACK, "frame overflow %zd > %d", gspca_dev->image_len + len,
frame->data_end - frame->data + len, gspca_dev->frsz);
frame->v4l2_buf.length);
packet_type = DISCARD_PACKET; packet_type = DISCARD_PACKET;
} else { } else {
memcpy(frame->data_end, data, len); memcpy(gspca_dev->image + gspca_dev->image_len,
frame->data_end += len; data, len);
gspca_dev->image_len += len;
} }
} }
gspca_dev->last_packet_type = packet_type; gspca_dev->last_packet_type = packet_type;
/* if last packet, wake up the application and advance in the queue */ /* if last packet, wake up the application and advance in the queue */
if (packet_type == LAST_PACKET) { if (packet_type == LAST_PACKET) {
frame->v4l2_buf.bytesused = frame->data_end - frame->data; i = gspca_dev->fr_i;
j = gspca_dev->fr_queue[i];
frame = &gspca_dev->frame[j];
frame->v4l2_buf.bytesused = gspca_dev->image_len;
frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_QUEUED; frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_QUEUED;
frame->v4l2_buf.flags |= V4L2_BUF_FLAG_DONE; frame->v4l2_buf.flags |= V4L2_BUF_FLAG_DONE;
wake_up_interruptible(&gspca_dev->wq); /* event = new frame */ wake_up_interruptible(&gspca_dev->wq); /* event = new frame */
i = (gspca_dev->fr_i + 1) % gspca_dev->nframes; i = (i + 1) % gspca_dev->nframes;
gspca_dev->fr_i = i; gspca_dev->fr_i = i;
PDEBUG(D_FRAM, "frame complete len:%d q:%d i:%d o:%d", PDEBUG(D_FRAM, "frame complete len:%d q:%d i:%d o:%d",
frame->v4l2_buf.bytesused, frame->v4l2_buf.bytesused,
@ -488,7 +477,13 @@ void gspca_frame_add(struct gspca_dev *gspca_dev,
i, i,
gspca_dev->fr_o); gspca_dev->fr_o);
j = gspca_dev->fr_queue[i]; j = gspca_dev->fr_queue[i];
gspca_dev->cur_frame = &gspca_dev->frame[j]; frame = &gspca_dev->frame[j];
if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS)
== V4L2_BUF_FLAG_QUEUED) {
gspca_dev->image = frame->data;
} else {
gspca_dev->image = NULL;
}
} }
} }
EXPORT_SYMBOL(gspca_frame_add); EXPORT_SYMBOL(gspca_frame_add);
@ -535,12 +530,12 @@ static int frame_alloc(struct gspca_dev *gspca_dev,
frame->v4l2_buf.length = frsz; frame->v4l2_buf.length = frsz;
frame->v4l2_buf.memory = gspca_dev->memory; frame->v4l2_buf.memory = gspca_dev->memory;
frame->v4l2_buf.sequence = 0; frame->v4l2_buf.sequence = 0;
frame->data = frame->data_end = frame->data = gspca_dev->frbuf + i * frsz;
gspca_dev->frbuf + i * frsz;
frame->v4l2_buf.m.offset = i * frsz; frame->v4l2_buf.m.offset = i * frsz;
} }
gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0; gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0;
gspca_dev->cur_frame = &gspca_dev->frame[0]; gspca_dev->image = NULL;
gspca_dev->image_len = 0;
gspca_dev->last_packet_type = DISCARD_PACKET; gspca_dev->last_packet_type = DISCARD_PACKET;
gspca_dev->sequence = 0; gspca_dev->sequence = 0;
return 0; return 0;
@ -1948,7 +1943,7 @@ static int vidioc_qbuf(struct file *file, void *priv,
i = gspca_dev->fr_q; i = gspca_dev->fr_q;
gspca_dev->fr_queue[i] = index; gspca_dev->fr_queue[i] = index;
if (gspca_dev->fr_i == i) if (gspca_dev->fr_i == i)
gspca_dev->cur_frame = frame; gspca_dev->image = frame->data;
gspca_dev->fr_q = (i + 1) % gspca_dev->nframes; gspca_dev->fr_q = (i + 1) % gspca_dev->nframes;
PDEBUG(D_FRAM, "qbuf q:%d i:%d o:%d", PDEBUG(D_FRAM, "qbuf q:%d i:%d o:%d",
gspca_dev->fr_q, gspca_dev->fr_q,

View file

@ -147,7 +147,6 @@ enum gspca_packet_type {
struct gspca_frame { struct gspca_frame {
__u8 *data; /* frame buffer */ __u8 *data; /* frame buffer */
__u8 *data_end; /* end of frame while filling */
int vma_use_count; int vma_use_count;
struct v4l2_buffer v4l2_buf; struct v4l2_buffer v4l2_buf;
}; };
@ -176,8 +175,9 @@ struct gspca_dev {
__u8 *frbuf; /* buffer for nframes */ __u8 *frbuf; /* buffer for nframes */
struct gspca_frame frame[GSPCA_MAX_FRAMES]; struct gspca_frame frame[GSPCA_MAX_FRAMES];
struct gspca_frame *cur_frame; /* frame beeing filled */ u8 *image; /* image beeing filled */
__u32 frsz; /* frame size */ __u32 frsz; /* frame size */
u32 image_len; /* current length of image */
char nframes; /* number of frames */ char nframes; /* number of frames */
char fr_i; /* frame being filled */ char fr_i; /* frame being filled */
char fr_q; /* next frame to queue */ char fr_q; /* next frame to queue */
@ -226,7 +226,6 @@ void gspca_frame_add(struct gspca_dev *gspca_dev,
enum gspca_packet_type packet_type, enum gspca_packet_type packet_type,
const u8 *data, const u8 *data,
int len); int len);
struct gspca_frame *gspca_get_i_frame(struct gspca_dev *gspca_dev);
#ifdef CONFIG_PM #ifdef CONFIG_PM
int gspca_suspend(struct usb_interface *intf, pm_message_t message); int gspca_suspend(struct usb_interface *intf, pm_message_t message);
int gspca_resume(struct usb_interface *intf); int gspca_resume(struct usb_interface *intf);

View file

@ -305,30 +305,28 @@ static void m5602_urb_complete(struct gspca_dev *gspca_dev,
sd->frame_count); sd->frame_count);
} else { } else {
struct gspca_frame *frame;
int cur_frame_len; int cur_frame_len;
frame = gspca_get_i_frame(gspca_dev); if (gspca_dev->image == NULL) {
if (frame == NULL) {
gspca_dev->last_packet_type = DISCARD_PACKET; gspca_dev->last_packet_type = DISCARD_PACKET;
return; return;
} }
cur_frame_len = frame->data_end - frame->data; cur_frame_len = gspca_dev->image_len;
/* Remove urb header */ /* Remove urb header */
data += 4; data += 4;
len -= 4; len -= 4;
if (cur_frame_len + len <= frame->v4l2_buf.length) { if (cur_frame_len + len <= gspca_dev->frsz) {
PDEBUG(D_FRAM, "Continuing frame %d copying %d bytes", PDEBUG(D_FRAM, "Continuing frame %d copying %d bytes",
sd->frame_count, len); sd->frame_count, len);
gspca_frame_add(gspca_dev, INTER_PACKET, gspca_frame_add(gspca_dev, INTER_PACKET,
data, len); data, len);
} else if (frame->v4l2_buf.length - cur_frame_len > 0) { } else {
/* Add the remaining data up to frame size */ /* Add the remaining data up to frame size */
gspca_frame_add(gspca_dev, INTER_PACKET, data, gspca_frame_add(gspca_dev, INTER_PACKET, data,
frame->v4l2_buf.length - cur_frame_len); gspca_dev->frsz - cur_frame_len);
} }
} }
} }

View file

@ -4162,7 +4162,6 @@ static void ovfx2_pkt_scan(struct gspca_dev *gspca_dev,
int len) /* iso packet length */ int len) /* iso packet length */
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
struct gspca_frame *frame;
gspca_frame_add(gspca_dev, INTER_PACKET, data, len); gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
@ -4172,9 +4171,8 @@ static void ovfx2_pkt_scan(struct gspca_dev *gspca_dev,
the sensor and bridge are still syncing, so drop it. */ the sensor and bridge are still syncing, so drop it. */
if (sd->first_frame) { if (sd->first_frame) {
sd->first_frame--; sd->first_frame--;
frame = gspca_get_i_frame(gspca_dev); if (gspca_dev->image_len <
if (!frame || (frame->data_end - frame->data) < sd->gspca_dev.width * sd->gspca_dev.height)
(sd->gspca_dev.width * sd->gspca_dev.height))
gspca_dev->last_packet_type = DISCARD_PACKET; gspca_dev->last_packet_type = DISCARD_PACKET;
} }
gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);

View file

@ -987,13 +987,10 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
data + 12, len - 12); data + 12, len - 12);
/* If this packet is marked as EOF, end the frame */ /* If this packet is marked as EOF, end the frame */
} else if (data[1] & UVC_STREAM_EOF) { } else if (data[1] & UVC_STREAM_EOF) {
struct gspca_frame *frame;
sd->last_pts = 0; sd->last_pts = 0;
frame = gspca_get_i_frame(gspca_dev); if (gspca_dev->image == NULL)
if (frame == NULL)
goto discard; goto discard;
if (frame->data_end - frame->data + (len - 12) != if (gspca_dev->image_len + len - 12 !=
gspca_dev->width * gspca_dev->height * 2) { gspca_dev->width * gspca_dev->height * 2) {
PDEBUG(D_PACK, "wrong sized frame"); PDEBUG(D_PACK, "wrong sized frame");
goto discard; goto discard;

View file

@ -804,7 +804,6 @@ static const unsigned char pac_jpeg_header2[] = {
}; };
static void pac_start_frame(struct gspca_dev *gspca_dev, static void pac_start_frame(struct gspca_dev *gspca_dev,
struct gspca_frame *frame,
__u16 lines, __u16 samples_per_line) __u16 lines, __u16 samples_per_line)
{ {
unsigned char tmpbuf[4]; unsigned char tmpbuf[4];
@ -829,15 +828,15 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
int len) /* iso packet length */ int len) /* iso packet length */
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
struct gspca_frame *frame; u8 *image;
unsigned char *sof; unsigned char *sof;
sof = pac_find_sof(&sd->sof_read, data, len); sof = pac_find_sof(&sd->sof_read, data, len);
if (sof) { if (sof) {
int n, lum_offset, footer_length; int n, lum_offset, footer_length;
frame = gspca_get_i_frame(gspca_dev); image = gspca_dev->image;
if (frame == NULL) { if (image == NULL) {
gspca_dev->last_packet_type = DISCARD_PACKET; gspca_dev->last_packet_type = DISCARD_PACKET;
return; return;
} }
@ -852,16 +851,15 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
/* Finish decoding current frame */ /* Finish decoding current frame */
n = (sof - data) - (footer_length + sizeof pac_sof_marker); n = (sof - data) - (footer_length + sizeof pac_sof_marker);
if (n < 0) { if (n < 0) {
frame->data_end += n; gspca_dev->image_len += n;
n = 0; n = 0;
} else {
gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
} }
gspca_frame_add(gspca_dev, INTER_PACKET, if (gspca_dev->last_packet_type != DISCARD_PACKET
data, n); && image[gspca_dev->image_len - 2] == 0xff
if (gspca_dev->last_packet_type != DISCARD_PACKET && && image[gspca_dev->image_len - 1] == 0xd9)
frame->data_end[-2] == 0xff && gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
frame->data_end[-1] == 0xd9)
gspca_frame_add(gspca_dev, LAST_PACKET,
NULL, 0);
n = sof - data; n = sof - data;
len -= n; len -= n;
@ -877,7 +875,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
/* Start the new frame with the jpeg header */ /* Start the new frame with the jpeg header */
/* The PAC7302 has the image rotated 90 degrees */ /* The PAC7302 has the image rotated 90 degrees */
pac_start_frame(gspca_dev, frame, pac_start_frame(gspca_dev,
gspca_dev->width, gspca_dev->height); gspca_dev->width, gspca_dev->height);
} }
gspca_frame_add(gspca_dev, INTER_PACKET, data, len); gspca_frame_add(gspca_dev, INTER_PACKET, data, len);

View file

@ -599,7 +599,6 @@ static const unsigned char pac_jpeg_header2[] = {
}; };
static void pac_start_frame(struct gspca_dev *gspca_dev, static void pac_start_frame(struct gspca_dev *gspca_dev,
struct gspca_frame *frame,
__u16 lines, __u16 samples_per_line) __u16 lines, __u16 samples_per_line)
{ {
unsigned char tmpbuf[4]; unsigned char tmpbuf[4];
@ -624,15 +623,15 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
int len) /* iso packet length */ int len) /* iso packet length */
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
u8 *image;
unsigned char *sof; unsigned char *sof;
struct gspca_frame *frame;
sof = pac_find_sof(&sd->sof_read, data, len); sof = pac_find_sof(&sd->sof_read, data, len);
if (sof) { if (sof) {
int n, lum_offset, footer_length; int n, lum_offset, footer_length;
frame = gspca_get_i_frame(gspca_dev); image = gspca_dev->image;
if (frame == NULL) { if (image == NULL) {
gspca_dev->last_packet_type = DISCARD_PACKET; gspca_dev->last_packet_type = DISCARD_PACKET;
return; return;
} }
@ -647,16 +646,15 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
/* Finish decoding current frame */ /* Finish decoding current frame */
n = (sof - data) - (footer_length + sizeof pac_sof_marker); n = (sof - data) - (footer_length + sizeof pac_sof_marker);
if (n < 0) { if (n < 0) {
frame->data_end += n; gspca_dev->image_len += n;
n = 0; n = 0;
} else {
gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
} }
gspca_frame_add(gspca_dev, INTER_PACKET, if (gspca_dev->last_packet_type != DISCARD_PACKET
data, n); && image[gspca_dev->image_len - 2] == 0xff
if (gspca_dev->last_packet_type != DISCARD_PACKET && && image[gspca_dev->image_len - 1] == 0xd9)
frame->data_end[-2] == 0xff && gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
frame->data_end[-1] == 0xd9)
gspca_frame_add(gspca_dev, LAST_PACKET,
NULL, 0);
n = sof - data; n = sof - data;
len -= n; len -= n;
@ -671,7 +669,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
atomic_set(&sd->avg_lum, -1); atomic_set(&sd->avg_lum, -1);
/* Start the new frame with the jpeg header */ /* Start the new frame with the jpeg header */
pac_start_frame(gspca_dev, frame, pac_start_frame(gspca_dev,
gspca_dev->height, gspca_dev->width); gspca_dev->height, gspca_dev->width);
} }
gspca_frame_add(gspca_dev, INTER_PACKET, data, len); gspca_frame_add(gspca_dev, INTER_PACKET, data, len);

View file

@ -1251,16 +1251,14 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) { if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) {
/* In raw mode we sometimes get some garbage after the frame /* In raw mode we sometimes get some garbage after the frame
ignore this */ ignore this */
struct gspca_frame *frame;
int used; int used;
int size = cam->cam_mode[gspca_dev->curr_mode].sizeimage; int size = cam->cam_mode[gspca_dev->curr_mode].sizeimage;
frame = gspca_get_i_frame(gspca_dev); if (gspca_dev->image == NULL) {
if (frame == NULL) {
gspca_dev->last_packet_type = DISCARD_PACKET; gspca_dev->last_packet_type = DISCARD_PACKET;
return; return;
} }
used = frame->data_end - frame->data; used = gspca_dev->image_len;
if (used + len > size) if (used + len > size)
len = size - used; len = size - used;
} }

View file

@ -3726,17 +3726,16 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
/* The vc0321 sends some additional data after sending the complete /* The vc0321 sends some additional data after sending the complete
* frame, we ignore this. */ * frame, we ignore this. */
if (sd->bridge == BRIDGE_VC0321) { if (sd->bridge == BRIDGE_VC0321) {
struct gspca_frame *frame; int size, l;
int l;
frame = gspca_get_i_frame(gspca_dev); if (gspca_dev->image == NULL) {
if (frame == NULL) {
gspca_dev->last_packet_type = DISCARD_PACKET; gspca_dev->last_packet_type = DISCARD_PACKET;
return; return;
} }
l = frame->data_end - frame->data; l = gspca_dev->image_len;
if (len > frame->v4l2_buf.length - l) size = gspca_dev->frsz;
len = frame->v4l2_buf.length - l; if (len > size - l)
len = size - l;
} }
gspca_frame_add(gspca_dev, INTER_PACKET, data, len); gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
} }