Skip to content

Commit

Permalink
[media] pwc: Remove software emulation of arbritary resolutions
Browse files Browse the repository at this point in the history
The pwc driver claims to support any resolution between 160x120
and 640x480, but emulates this by simply drawing a black border
around the image. Userspace can draw its own black border if it
really wants one.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
  • Loading branch information
Hans de Goede authored and Mauro Carvalho Chehab committed Jan 6, 2012
1 parent a08d2c7 commit 795e6eb
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 222 deletions.
10 changes: 0 additions & 10 deletions Documentation/feature-removal-schedule.txt
Original file line number Diff line number Diff line change
Expand Up @@ -460,16 +460,6 @@ Who: Jean Delvare <khali@linux-fr.org>

----------------------------

What: Software emulation of arbritary resolutions in the pwc driver
When: 3.3
Why: The pwc driver claims to support any resolution between 160x120
and 640x480, but emulates this by simply drawing a black border
around the image. Userspace can draw its own black border if it
really wants one.
Who: Hans de Goede <hdegoede@redhat.com>

----------------------------

What: For VIDIOC_S_FREQUENCY the type field must match the device node's type.
If not, return -EINVAL.
When: 3.2
Expand Down
69 changes: 13 additions & 56 deletions drivers/media/video/pwc/pwc-ctrl.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,6 @@ static struct Nala_table_entry Nala_table[PSZ_MAX][PWC_FPS_MAX_NALA] =
#include "pwc-nala.h"
};

static void pwc_set_image_buffer_size(struct pwc_device *pdev);

/****************************************************************************/

static int _send_control_msg(struct pwc_device *pdev,
Expand Down Expand Up @@ -221,8 +219,9 @@ static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
/* Set various parameters */
pdev->vframes = frames;
pdev->valternate = pEntry->alternate;
pdev->image = pwc_image_sizes[size];
pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2;
pdev->width = pwc_image_sizes[size][0];
pdev->height = pwc_image_sizes[size][1];
pdev->frame_size = (pdev->width * pdev->height * 3) / 2;
if (pEntry->compressed) {
if (pdev->release < 5) { /* 4 fold compression */
pdev->vbandlength = 528;
Expand Down Expand Up @@ -282,12 +281,13 @@ static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames,
/* Set various parameters */
pdev->vframes = frames;
pdev->valternate = pChoose->alternate;
pdev->image = pwc_image_sizes[size];
pdev->width = pwc_image_sizes[size][0];
pdev->height = pwc_image_sizes[size][1];
pdev->vbandlength = pChoose->bandlength;
if (pChoose->bandlength > 0)
pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4;
pdev->frame_size = (pChoose->bandlength * pdev->height) / 4;
else
pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
pdev->frame_size = (pdev->width * pdev->height * 12) / 8;
return 0;
}

Expand Down Expand Up @@ -339,37 +339,25 @@ static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames,
/* All set and go */
pdev->vframes = frames;
pdev->valternate = pChoose->alternate;
pdev->image = pwc_image_sizes[size];
pdev->width = pwc_image_sizes[size][0];
pdev->height = pwc_image_sizes[size][1];
pdev->vbandlength = pChoose->bandlength;
if (pdev->vbandlength > 0)
pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4;
pdev->frame_size = (pdev->vbandlength * pdev->height) / 4;
else
pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
pdev->frame_size = (pdev->width * pdev->height * 12) / 8;
PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vbandlength=%d\n",
pdev->frame_size, pdev->vframes, size, pdev->vbandlength);
return 0;
}



/**
@pdev: device structure
@width: viewport width
@height: viewport height
@frame: framerate, in fps
@compression: preferred compression ratio
*/
int pwc_set_video_mode(struct pwc_device *pdev, int width, int height,
int frames, int compression)
{
int ret, size;

PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n", width, height, frames, pdev->pixfmt);
size = pwc_decode_size(pdev, width, height);
if (size < 0) {
PWC_DEBUG_MODULE("Could not find suitable size.\n");
return -ERANGE;
}
size = pwc_get_size(pdev, width, height);
PWC_TRACE("decode_size = %d.\n", size);

if (DEVICE_USE_CODEC1(pdev->type)) {
Expand All @@ -385,12 +373,9 @@ int pwc_set_video_mode(struct pwc_device *pdev, int width, int height,
PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
return ret;
}
pdev->view.x = width;
pdev->view.y = height;
pdev->vcompression = compression;
pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size;
pwc_set_image_buffer_size(pdev);
PWC_DEBUG_SIZE("Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y);
PWC_DEBUG_SIZE("Set resolution to %dx%d\n", pdev->width, pdev->height);
return 0;
}

Expand Down Expand Up @@ -447,34 +432,6 @@ unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned i
return ret;
}

static void pwc_set_image_buffer_size(struct pwc_device *pdev)
{
int factor = 0;

/* for V4L2_PIX_FMT_YUV420 */
switch (pdev->pixfmt) {
case V4L2_PIX_FMT_YUV420:
factor = 6;
break;
case V4L2_PIX_FMT_PWC1:
case V4L2_PIX_FMT_PWC2:
factor = 6; /* can be uncompressed YUV420P */
break;
}

/* Set sizes in bytes */
pdev->image.size = pdev->image.x * pdev->image.y * factor / 4;
pdev->view.size = pdev->view.x * pdev->view.y * factor / 4;

/* Align offset, or you'll get some very weird results in
YUV420 mode... x must be multiple of 4 (to get the Y's in
place), and y even (or you'll mixup U & V). This is less of a
problem for YUV420P.
*/
pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC;
pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE;
}

int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
{
int ret;
Expand Down
29 changes: 10 additions & 19 deletions drivers/media/video/pwc/pwc-dec23.c
Original file line number Diff line number Diff line change
Expand Up @@ -656,18 +656,14 @@ static void DecompressBand23(struct pwc_dec23_private *pdec,
*
* Uncompress a pwc23 buffer.
*
* pwc.view: size of the image wanted
* pwc.image: size of the image returned by the camera
* pwc.offset: (x,y) to displayer image in the view
*
* src: raw data
* dst: image output
*/
void pwc_dec23_decompress(const struct pwc_device *pwc,
const void *src,
void *dst)
{
int bandlines_left, stride, bytes_per_block;
int bandlines_left, bytes_per_block;
struct pwc_dec23_private *pdec = pwc->decompress_data;

/* YUV420P image format */
Expand All @@ -678,28 +674,23 @@ void pwc_dec23_decompress(const struct pwc_device *pwc,

mutex_lock(&pdec->lock);

bandlines_left = pwc->image.y / 4;
bytes_per_block = pwc->view.x * 4;
plane_size = pwc->view.x * pwc->view.y;

/* offset in Y plane */
stride = pwc->view.x * pwc->offset.y;
pout_planar_y = dst + stride + pwc->offset.x;
bandlines_left = pwc->height / 4;
bytes_per_block = pwc->width * 4;
plane_size = pwc->height * pwc->width;

/* offsets in U/V planes */
stride = (pwc->view.x * pwc->offset.y) / 4 + pwc->offset.x / 2;
pout_planar_u = dst + plane_size + stride;
pout_planar_v = dst + plane_size + plane_size / 4 + stride;
pout_planar_y = dst;
pout_planar_u = dst + plane_size;
pout_planar_v = dst + plane_size + plane_size / 4;

while (bandlines_left--) {
DecompressBand23(pwc->decompress_data,
src,
pout_planar_y, pout_planar_u, pout_planar_v,
pwc->image.x, pwc->view.x);
pwc->width, pwc->width);
src += pwc->vbandlength;
pout_planar_y += bytes_per_block;
pout_planar_u += pwc->view.x;
pout_planar_v += pwc->view.x;
pout_planar_u += pwc->width;
pout_planar_v += pwc->width;
}
mutex_unlock(&pdec->lock);
}
10 changes: 6 additions & 4 deletions drivers/media/video/pwc/pwc-if.c
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,7 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
unsigned int sizes[], void *alloc_ctxs[])
{
struct pwc_device *pdev = vb2_get_drv_priv(vq);
int size;

if (*nbuffers < MIN_FRAMES)
*nbuffers = MIN_FRAMES;
Expand All @@ -664,7 +665,9 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,

*nplanes = 1;

sizes[0] = PAGE_ALIGN((pdev->abs_max.x * pdev->abs_max.y * 3) / 2);
size = pwc_get_size(pdev, MAX_WIDTH, MAX_HEIGHT);
sizes[0] = PAGE_ALIGN(pwc_image_sizes[size][0] *
pwc_image_sizes[size][1] * 3 / 2);

return 0;
}
Expand Down Expand Up @@ -742,7 +745,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
pwc_camera_power(pdev, 1);
if (pdev->power_save) {
/* Restore video mode */
pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y,
pwc_set_video_mode(pdev, pdev->width, pdev->height,
pdev->vframes, pdev->vcompression);
}
pwc_set_leds(pdev, led_on, led_off);
Expand Down Expand Up @@ -1056,7 +1059,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
}
pdev->type = type_id;
pdev->vframes = default_fps;
strcpy(pdev->serial, serial_number);
pdev->features = features;
pwc_construct(pdev); /* set min/max sizes correct */

Expand Down Expand Up @@ -1119,7 +1121,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pwc_set_leds(pdev, 0, 0);

/* Setup intial videomode */
rc = pwc_set_video_mode(pdev, pdev->view_max.x, pdev->view_max.y,
rc = pwc_set_video_mode(pdev, MAX_WIDTH, MAX_HEIGHT,
pdev->vframes, pdev->vcompression);
if (rc)
goto err_free_mem;
Expand Down
87 changes: 26 additions & 61 deletions drivers/media/video/pwc/pwc-misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,67 +27,47 @@

#include "pwc.h"

const struct pwc_coord pwc_image_sizes[PSZ_MAX] =
const int pwc_image_sizes[PSZ_MAX][2] =
{
{ 128, 96, 0 }, /* sqcif */
{ 160, 120, 0 }, /* qsif */
{ 176, 144, 0 }, /* qcif */
{ 320, 240, 0 }, /* sif */
{ 352, 288, 0 }, /* cif */
{ 640, 480, 0 }, /* vga */
{ 128, 96 }, /* sqcif */
{ 160, 120 }, /* qsif */
{ 176, 144 }, /* qcif */
{ 320, 240 }, /* sif */
{ 352, 288 }, /* cif */
{ 640, 480 }, /* vga */
};

/* x,y -> PSZ_ */
int pwc_decode_size(struct pwc_device *pdev, int width, int height)
int pwc_get_size(struct pwc_device *pdev, int width, int height)
{
int i, find;

/* Make sure we don't go beyond our max size.
NB: we have different limits for RAW and normal modes. In case
you don't have the decompressor loaded or use RAW mode,
the maximum viewable size is smaller.
*/
if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
{
if (width > pdev->abs_max.x || height > pdev->abs_max.y)
{
PWC_DEBUG_SIZE("VIDEO_PALETTE_RAW: going beyond abs_max.\n");
return -1;
}
}
else
{
if (width > pdev->view_max.x || height > pdev->view_max.y)
{
PWC_DEBUG_SIZE("VIDEO_PALETTE_not RAW: going beyond view_max.\n");
return -1;
}
}
int i;

/* Find the largest size supported by the camera that fits into the
requested size.
*/
find = -1;
requested size. */
for (i = PSZ_MAX - 1; i >= 0; i--) {
if (!(pdev->image_mask & (1 << i)))
continue;

if (pwc_image_sizes[i][0] <= width &&
pwc_image_sizes[i][1] <= height)
return i;
}

/* No mode found, return the smallest mode we have */
for (i = 0; i < PSZ_MAX; i++) {
if (pdev->image_mask & (1 << i)) {
if (pwc_image_sizes[i].x <= width && pwc_image_sizes[i].y <= height)
find = i;
}
if (pdev->image_mask & (1 << i))
return i;
}
return find;

/* Never reached there always is atleast one supported mode */
return 0;
}

/* initialize variables depending on type and decompressor*/
/* initialize variables depending on type and decompressor */
void pwc_construct(struct pwc_device *pdev)
{
if (DEVICE_USE_CODEC1(pdev->type)) {

pdev->view_min.x = 128;
pdev->view_min.y = 96;
pdev->view_max.x = 352;
pdev->view_max.y = 288;
pdev->abs_max.x = 352;
pdev->abs_max.y = 288;
pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QCIF | 1 << PSZ_CIF;
pdev->vcinterface = 2;
pdev->vendpoint = 4;
Expand All @@ -96,34 +76,19 @@ void pwc_construct(struct pwc_device *pdev)

} else if (DEVICE_USE_CODEC3(pdev->type)) {

pdev->view_min.x = 160;
pdev->view_min.y = 120;
pdev->view_max.x = 640;
pdev->view_max.y = 480;
pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA;
pdev->abs_max.x = 640;
pdev->abs_max.y = 480;
pdev->vcinterface = 3;
pdev->vendpoint = 5;
pdev->frame_header_size = TOUCAM_HEADER_SIZE;
pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE;

} else /* if (DEVICE_USE_CODEC2(pdev->type)) */ {

pdev->view_min.x = 128;
pdev->view_min.y = 96;
/* Anthill bug #38: PWC always reports max size, even without PWCX */
pdev->view_max.x = 640;
pdev->view_max.y = 480;
pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA;
pdev->abs_max.x = 640;
pdev->abs_max.y = 480;
pdev->vcinterface = 3;
pdev->vendpoint = 4;
pdev->frame_header_size = 0;
pdev->frame_trailer_size = 0;
}
pdev->pixfmt = V4L2_PIX_FMT_YUV420; /* default */
pdev->view_min.size = pdev->view_min.x * pdev->view_min.y;
pdev->view_max.size = pdev->view_max.x * pdev->view_max.y;
}
Loading

0 comments on commit 795e6eb

Please sign in to comment.