[Remix OS for PC] ftvm:
Please, can you help me!

This long I'm looking for a solution to put in the place the integrated camera of the pc that persists to be upside down!

I was able to find information that could be useful to developers but I do not know how to apply them with Remix OS!

Is anyone could help me please?

I found sources to patch the camera on a site of ubuntu.

https://ubuntuforums.org/showthread.php?t=838210

I do not know which of these patches would likely work with my equipment

Is there someone who knows it in Linux or android who can give me information

Or is that the developer of Remix OS could do some things for me to solve this problem?

Thank you for your attention

cordially

Jean Pierre

FIRST SOLUTION (MIRRORED IMAGES)

# modified June 26, 2008

Code:

diff -uN UVCVIDEO_v0.1.0/uvc_video.c UVCVIDEO_patched/uvc_video.c

--- UVCVIDEO_v0.1.0/uvc_video.c 2008-06-26 10:41:01.000000000 +0200

+++ UVCVIDEO_patched/uvc_video.c 2008-06-26 15:33:33.000000000 +0200

@@ -371,23 +371,92 @@

return data[0];

}

+/* This patched function allows to overturn video images from an upside-down

+ * orientation to a normal one with mirrored effect. The conversion simply

+ * consists in reversing the order of the rows of imagines.

+ * This patch performs its job just once for each frame and only when current

+ * frame is completed, but each time it is required to allocate memory in order

+ * to store a copy of that frame.

+ * This patch should work with all YUV image formats.

+ */

static void uvc_video_decode_data(struct uvc_video_device *video,

struct uvc_buffer *buf, const __u8 *data, int len)

{

struct uvc_video_queue *queue = &video->queue;

unsigned int maxlen, nbytes;

void *mem;

+ /* Patch variables */

+ __u8 *mem_tmp, *ptr_tmp;

+ int i, k, row_size;

if (len <= 0)

return;

/* Copy the video data to the buffer. */

+ /* How many bytes are needed to complete the buffer? */

maxlen = buf->buf.length - buf->buf.bytesused;

+ /* Where do pixels stored in "data" have to be copied? */

mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused;

+ /* How many bytes really can be copied into "mem"? */

nbytes = min((unsigned int)len, maxlen);

+ /* "nbytes" are copied from "data" to "mem" buffer.

+ * "data" stores a sequence of pixels coming from the video source.

+ * This sequence is not a full frame or a full row of pixel, but just an

+ * ordered vector of pixels (from top-left to bottom-right), whose

+ * represents just an area of the current frame.

+ * This function has to be called hundreds of times before a frame is

+ * completed and "nbytes" is not constant! Each time "data" contains the

+ * next part of the frame. At the end data stored in "mem" buffer will

+ * be used by the application who requested the video stream.

+ */

memcpy(mem, data, nbytes);

buf->buf.bytesused += nbytes;

+ /* Have the last copied bytes completed the current frame? */

+ if (nbytes == maxlen) {

+ /* Area where to save the upper half part of the original frame

+ * (just half in order to speed up the patch) before reversing.

+ */

+ mem_tmp = (__u8 *) kmalloc(buf->buf.bytesused / 2, GFP_ATOMIC);

+ if (mem_tmp != NULL ) {

+ /* Copy top-half part of frame in a temporary buffer */

+ memcpy(mem_tmp, queue->mem + buf->buf.m.offset,

+ buf->buf.bytesused / 2);

+ /* "row_size" does not depend only on the width of the

+ * frame, but also on the pixel color depth (bpp).

+ */

+ row_size = video->streaming->cur_frame->wWidth *

+ video->streaming->format->bpp / 8;

+ /* The following cycle just copy full frame rows from

+ * the last one stored in "mem" (and going up) to the

+ * first one (and going down) stored in "mem" itself.

+ */

+ ptr_tmp = queue->mem + buf->buf.m.offset

+ + buf->buf.bytesused / 2;

+ /* When the top-half of the frame has been reversed,

+ * rows are copied from the last one stored in "mem_tmp"

+ * (and going up) into the bottom half part of "mem"

+ * buffer.

+ */

+ for (i = 0, k = buf->buf.bytesused / 2 - row_size;

+ i < buf->buf.bytesused;

+ i += row_size, k -= row_size) {

+ /* If the top-half of the frame has been

+ * revesed, then it is needed to split the

+ * source buffer from "mem" to "mem_tmp".

+ */

+ if (i == buf->buf.bytesused / 2) {

+ ptr_tmp = mem_tmp;

+ k = buf->buf.bytesused / 2 - row_size;

+ }

+ memcpy(queue->mem + buf->buf.m.offset + i,

+ ptr_tmp + k,

+ row_size);

+ }

+ /* For this frame "mem_tmp" is not needed any more. */

+ kfree(mem_tmp);

+ }

+ }

/* Complete the current frame if the buffer size was exceeded. */

if (len > maxlen) {

uvc_trace(UVC_TRACE_FRAME, "Frame complete (overflow).\n");

FIRST SOLUTION (NOT MIRRORED IMAGES)

# modified June 26, 2008

Code:

diff -uN UVCVIDEO_v0.1.0/uvc_video.c UVCVIDEO_patched/uvc_video.c

--- UVCVIDEO_v0.1.0/uvc_video.c 2008-06-26 10:41:01.000000000 +0200

+++ UVCVIDEO_patched/uvc_video.c 2008-06-26 15:33:33.000000000 +0200

@@ -371,23 +371,105 @@

return data[0];

}

+/* This patch should work ONLY with YUY2 image formats, also known as YUYV or

+ * YUV422 formats.

+ * This patched function allows to overturn video images from an upside-down

+ * orientation to a normal one. The conversion consists in copying 4 bytes at a

+ * time (Y0,U0,Y1,V0) corresponding to 2 pixels, in a bottom-up direction, from

+ * the frame (coming from the video source) to the buffer that will be used by

+ * the application requesting the video stream. But in order to satisfy the YUY2

+ * image format byte has to be copied in this way: Y1 U0 Y0 VO.

+ * This patch performs its job just once for each frame and only when current

+ * frame is completed, but each time it is required to allocate memory in order

+ * to store a copy of that frame.

+ */

static void uvc_video_decode_data(struct uvc_video_device *video,

struct uvc_buffer *buf, const __u8 *data, int len)

{

struct uvc_video_queue *queue = &video->queue;

unsigned int maxlen, nbytes;

void *mem;

+ /* Patch variables */

+ __u8 *mem_tmp, *ptr_tmp;

+ int i, k, pixel_size;

if (len <= 0)

return;

/* Copy the video data to the buffer. */

+ /* How many bytes are needed to complete the buffer? */

maxlen = buf->buf.length - buf->buf.bytesused;

+ /* Where do pixels stored in "data" have to be copied? */

mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused;

+ /* How many bytes really can be copied into "mem"? */

nbytes = min((unsigned int)len, maxlen);

+ /* "nbytes" are copied from "data" to "mem" buffer.

+ * "data" stores a sequence of pixels coming from the video source.

+ * This sequence is not a full frame or a full row of pixel, but just

+ * an ordered vector of pixels (from top-left to bottom-right), whose

+ * represents just an area of the current frame.

+ * This function has to be called hundreds of times before a frame is

+ * completed and "nbytes" is not constant! Each time "data" contains the

+ * next part of the frame. At the end data stored in "mem" buffer will

+ * be used by the application who requested the video stream.

+ */

memcpy(mem, data, nbytes);

buf->buf.bytesused += nbytes;

+ /* Have the last copied bytes completed the current frame? */

+ if (nbytes == maxlen) {

+ /* Area where to save the original frame before manipulation. */

+ mem_tmp = (__u8 *) kmalloc(buf->buf.bytesused / 2, GFP_ATOMIC);

+ if (mem_tmp != NULL ) {

+ /* Copy the original frame in a temporary buffer. */

+ memcpy(mem_tmp, queue->mem + buf->buf.m.offset,

+ buf->buf.bytesused / 2);

+ /* "pixel_size" depens on the pixel color depth (bpp),

+ * but in YUY2 image format is constant and equal to 2.

+ */

+ pixel_size = video->streaming->format->bpp / 8;

+ /* The following loop copy 2 pixels at a time (4 bytes

+ * in YUY2 format) from the last two stored in "mem"

+ * (and going back) to the first two (and going on)

+ * stored in "mem" itself following a sort of YUY2

+ * algorithm.

+ */

+ ptr_tmp = queue->mem + buf->buf.m.offset

+ + buf->buf.bytesused / 2;

+ /* When the top-half of the frame has been reversed,

+ * rows are copied from the last one stored in "mem_tmp"

+ * (and going up) into the bottom half part of "mem"

+ * buffer.

+ */

+ for (i = 0, k = buf->buf.bytesused / 2 - 2 * pixel_size;

+ i < buf->buf.bytesused;

+ i += 2 * pixel_size, k -= 2 * pixel_size){

+ /* If the top-half of the frame has been

+ * revesed, then it is needed to split the

+ * source buffer from "mem" to "mem_tmp".

+ */

+ if (i == buf->buf.bytesused / 2) {

+ ptr_tmp = mem_tmp;

+ k = buf->buf.bytesused / 2

+ - 2 * pixel_size;

+ }

+ /* The order of copied bytes is changed from

+ * (Y0 U0 Y1 V1) to (Y1 U0 Y0 V1), i.e. from

+ * (#0 #1 #2 #3) to (#2 #1 #0 #3).

+ */

+ ((__u8 *)(queue->mem+buf->buf.m.offset + i))[0] =

+ ((__u8 *)(ptr_tmp + k))[2];

+ ((__u8 *)(queue->mem+buf->buf.m.offset + i))[1] =

+ ((__u8 *)(ptr_tmp + k))[1];

+ ((__u8 *)(queue->mem+buf->buf.m.offset + i))[2] =

+ ((__u8 *)(ptr_tmp + k))[0];

+ ((__u8 *)(queue->mem+buf->buf.m.offset + i))[3] =

+ ((__u8 *)(ptr_tmp + k))[3];

+ }

+ /* For this frame "mem_tmp" is not needed any more. */

+ kfree(mem_tmp);

+ }

+ }

/* Complete the current frame if the buffer size was exceeded. */

if (len > maxlen) {

uvc_trace(UVC_TRACE_FRAME, "Frame complete (overflow).\n");

SECOND SOLUTION (MIRRORED IMAGES)

# modified June 26, 2008

Code:

diff -uN UVCVIDEO_v0.1.0/uvc_video.c UVCVIDEO_patched/uvc_video.c

--- UVCVIDEO_v0.1.0/uvc_video.c 2008-06-26 10:41:01.000000000 +0200

+++ UVCVIDEO_patched/uvc_video.c 2008-06-26 14:03:58.000000000 +0200

@@ -371,23 +371,91 @@

return data[0];

}

+/* This patched function allows to overturn video images from an upside-down

+ * orientation to a normal one with mirrored effect. The conversion consists in

+ * reversing the order of the rows of imagines.

+ * "data" stores a sequence of pixels coming from the video source.

+ * This sequence is not a full frame or a full row of pixel, but just an

+ * ordered vector of pixels (from top-left to bottom-right), whose

+ * represents just an area of the current frame and which size ("nbytes") is

+ * not constant. In fact this function has to be called hundreds of times

+ * before a frame is completed. Each time "data" contains the next part of the

+ * current frame (upside-down). At the end data stored in "mem" buffer will be

+ * used by the application who requested the video stream.

+ * No memory allocation is needed because pixel order is modified directly

+ * while copying from "data" into "mem" buffer (i.e. in each call of this

+ * function), and not just once when the frame is already completed.

+ * This patch should work with all YUV image formats.

+ */

static void uvc_video_decode_data(struct uvc_video_device *video,

struct uvc_buffer *buf, const __u8 *data, int len)

{

struct uvc_video_queue *queue = &video->queue;

unsigned int maxlen, nbytes;

void *mem;

+ /* Patch variables */

+ unsigned int row_size, to_be_copied, shift_right;

if (len <= 0)

return;

/* Copy the video data to the buffer. */

+ /* How many bytes are needed to complete the buffer? */

maxlen = buf->buf.length - buf->buf.bytesused;

+ /* Where do pixels stored in "data" have to be copied? */

mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused;

+ /* How many bytes really can be copied into "mem"? */

nbytes = min((unsigned int)len, maxlen);

- memcpy(mem, data, nbytes);

- buf->buf.bytesused += nbytes;

+ /* "row_size" is the number of bytes required to store a full row of

+ * the frame.

+ */

+ row_size = video->streaming->cur_frame->wWidth *

+ video->streaming->format->bpp / 8;

+ /* Each loop "nbytes" is decremented of the number of bytes just copied.

+ * So are there any other bytes to be copied?

+ */

+ while (nbytes > 0) {

+ /* As the rows of modified frames have to be fulfilled from

+ * bottom-left to top-right, each cycle tries to complete a

+ * single row.

+ * In this cycle where is it needed to start to store bytes

+ * within the selected row? From the beginning or shifted

+ * right? Because other bytes could have been already stored in

+ * that row without completing it, so it could be needed a right

+ * shift.

+ */

+ shift_right = buf->buf.bytesused % row_size;

+ /* In this cycle how many byte can we copy in the selected row?

+ */

+ if (nbytes > row_size - shift_right)

+ to_be_copied = row_size - shift_right ;

+ else

+ to_be_copied = nbytes;

+ /* "queue->mem + buf->buf.m.offset" is the base-address where to

+ * start to store the current frame. This address refers to a

+ * preallocated area (just for a sigle frame) taking part in a

+ * circular buffer, where to store a fixed number of sequent

+ * frames.

+ */

+ memcpy(queue->mem + buf->buf.m.offset

+ /* Go to the end of this frame. */

+ + row_size * video->streaming->cur_frame->wHeight

+ /* Go back for the number of bytes corrisponding to the

+ * already fully completed rows.

+ */

+ - (buf->buf.bytesused - shift_right)

+ /* Go back at the starting point of the upper row. */

+ - row_size

+ /* Shift right on this row if it is needed. */

+ + shift_right,

+ data,

+ to_be_copied );

+ /* Update "data", "byteused" and "nbytes" values. */

+ data += to_be_copied;

+ buf->buf.bytesused += to_be_copied ;

+ nbytes -= to_be_copied;

+ }

/* Complete the current frame if the buffer size was exceeded. */

if (len > maxlen) {

uvc_trace(UVC_TRACE_FRAME, "Frame complete (overflow).\n");

SECOND SOLUTION (NOT MIRRORED IMAGES)

# modified June 26, 2008

Code:

diff -uN UVCVIDEO_v0.1.0/uvc_video.c UVCVIDEO_patched/uvc_video.c

--- UVCVIDEO_v0.1.0/uvc_video.c 2008-06-26 10:41:01.000000000 +0200

+++ UVCVIDEO_patched/uvc_video.c 2008-06-26 14:03:58.000000000 +0200

@@ -371,23 +371,81 @@

return data[0];

}

+/* This patch should work ONLY with YUY2 image formats, also known as YUYV or

+ * YUV422 formats.

+ * This patched function allows to overturn video images from an upside-down

+ * orientation to a normal one. The conversion consists in copying 4 bytes at a

+ * time (Y0,U0,Y1,V0) corresponding to 2 pixels from the frame (coming from the

+ * video source) to the buffer that will be used by the application requesting

+ * the video stream. But in order to satisfy the YUY2 image format byte has to

+ * be copied in this way: Y1 U0 Y0 VO. Bytes are copied in a bottom-up

+ * direction into the reversed frame.

+ * "data" stores a sequence of pixels coming from the video source.

+ * This sequence is not a full frame or a full row of pixel, but just an

+ * ordered vector of pixels (from top-left to bottom-right), whose

+ * represents just an area of the current frame and which size ("nbytes") is

+ * not constant. In fact this function has to be called hundreds of times

+ * before a frame is completed. Each time "data" contains the next part of the

+ * current frame (upside-down). At the end data stored in "mem" buffer will be

+ * used by the application who requested the video stream.

+ * No memory allocation is needed because pixel order is modified directly

+ * while copying from "data" into "mem" buffer (i.e. in each call of this

+ * function), and not just once when the frame is already completed.

+ */

static void uvc_video_decode_data(struct uvc_video_device *video,

struct uvc_buffer *buf, const __u8 *data, int len)

{

struct uvc_video_queue *queue = &video->queue;

unsigned int maxlen, nbytes;

void *mem;

+ /* Patch variables */

+ unsigned int i, pixel_size;

+ __u8 *ptr_tmp;

if (len <= 0)

return;

/* Copy the video data to the buffer. */

+ /* How many bytes are needed to complete the buffer? */

maxlen = buf->buf.length - buf->buf.bytesused;

+ /* Where do pixels stored in "data" have to be copied? */

mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused;

+ /* How many bytes really can be copied into "mem"? */

nbytes = min((unsigned int)len, maxlen);

- memcpy(mem, data, nbytes);

- buf->buf.bytesused += nbytes;

+ /* "pixel_size" depens on the pixel color depth (bpp),

+ * but in YUY2 image format is constant and equal to 2.

+ */

+ pixel_size = video->streaming->format->bpp / 8;

+ /* In each loop 4 bytes are modified and copied into "mem" buffer. */

+ for (i = 0; i < nbytes; i += 2 * pixel_size) {

+ /* "queue->mem + buf->buf.m.offset" is the base-address

+ * where to start to store the current frame. This

+ * address refers to a preallocated area (just for a

+ * sigle frame) taking part in a circular buffer, where

+ * to store a fixed number of sequent frames.

+ */

+ ptr_tmp = (__u8 *)(queue->mem + buf->buf.m.offset

+ /* Go to the end of this frame. */

+ + video->streaming->cur_frame->wWidth * pixel_size

+ * video->streaming->cur_frame->wHeight

+ /* Go back for the number of already copied bytes. */

+ - buf->buf.bytesused

+ /* Go back for the number of bytes (4 bytes) to be

+ * copied in this cycle.

+ */

+ - 2 * pixel_size);

+ /* The order of copied bytes is changed from

+ * (Y0 U0 Y1 V1) to (Y1 U0 Y0 V1), i.e. from

+ * (#0 #1 #2 #3) to (#2 #1 #0 #3).

+ */

+ ptr_tmp[0] = ((__u8 *)(data + i))[2];

+ ptr_tmp[1] = ((__u8 *)(data + i))[1];

+ ptr_tmp[2] = ((__u8 *)(data + i))[0];

+ ptr_tmp[3] = ((__u8 *)(data + i))[3];

+ /* Update "byteused" value. */

+ buf->buf.bytesused += 2 * pixel_size;

+ }

/* Complete the current frame if the buffer size was exceeded. */

if (len > maxlen) {

uvc_trace(UVC_TRACE_FRAME, "Frame complete (overflow).\n");

"

Well, now the worst part has been done!!!

We just need to compile our modded file and to install the new driver, so from shell you have to go to the "Trunk" directory and type:

Code:

make

there shouldn't be errors!!

Then, ONLY if you are using one of the Ubuntu distributions (ubuntu, kubuntu, etc.), open with you editor the "Makefile" and change the following line:

Code:

INSTALL_MOD_DIR := usb/media

with

Code:

INSTALL_MOD_DIR := ubuntu/media/usbvideo

Now we just need to remove uvcvideo module (if you have previously installed it):

Code:

sudo modprobe -r uvcvideo

Then:

Code:

sudo make install

sudo cp uvcvideo.ko /lib/modules/`uname -r`/ubuntu/media/usbvideo/

sudo cp uvcvideo.ko /lib/modules/`uname -r`/usb/media/

sudo depmod -ae

sudo modprobe -f uvcvideo

Now everything should work!!!

Let me know!!

And please try both solutions..

in case you don't see any difference just use the SECOND solution (mirrored or not, has you prefer), it should be the safest!!

Good luck,

enjoy your webcam!!

"