LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - General (https://www.linuxquestions.org/questions/linux-general-1/)
-   -   Any libuvc users around? (https://www.linuxquestions.org/questions/linux-general-1/any-libuvc-users-around-4175721570/)

ab1jx 02-01-2023 07:28 PM

Any libuvc users around?
 
UVC is a standard for doing video over USB, if you look in ports/packages of your distribution you'll probably find it, it's also in Windows and I think Android. There's a FOSS Linux version of course at https://github.com/libuvc/libuvc I've only been using Linux for 25 years or so, this beast is strange. I've had about as much luck reading the headers as the Doxygen documentation, but that's typical. It's mostly for video webcams apparently but it's also possible to get single frames out of it. Most people probably use it for simple webcams, I bought an Svbony SV205 camera for astronomical use, which is what a Chinese company made by mounting a Sony IMX179 sensor in a housing which fits into a telescope eyepiece tube. https://www.svbony.com/sv205-astronomy-camera/ Normally you use a bigger telescope to gather more light, with this the promise is that you can combine many exposures. Of course the Earth is rotating so you need to call gettimeofday() for each and carefully overlay them, but I haven't gotten that far.

When I run the best program I can come up with it captures several images at different resolutions then crashes, usually a segfault. Trying to run gdb on the core file it seems to be multithreaded and I'm not sure how to debug that. I'm on a Raspberry Pi 3B with 4 cores so there's a thread for each core, but that comes from somewhere in the library, it's nothing I added. After it's done 1 - 20 or so images it crashes, maybe the Pi isn't fast enough, but really it doesn't need to hurry so crashing is silly. An image a minute could work as long as they overlay correctly. I store the images on the sd/hard drive.

res4: No such file or directory.
[New LWP 21100]
[New LWP 21097]
[New LWP 21096]
[New LWP 21098]
Core was generated by `./dem4'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0xb6ed232c in ?? ()
[Current thread is 1 (LWP 21100)]

Anyway, does anybody know of a forum where such things are commonly discussed? I don't find any mention of uvc here at all.

This is another option (recently discovered): https://www.astrodmx-capture.org.uk/

teckk 02-02-2023 02:42 PM

My first thought is, have you tried v4l, v4l-utils.
https://linuxtv.org/

I looked at that source. You built that successfully with cmake and then it crashes?

There are some examples:
https://libuvc.github.io/libuvc/
https://github.com/libuvc/libuvc/blo.../src/example.c

You might want to tell some more about how you are using it. And what your project code looks like.

I've never used it.

ab1jx 02-02-2023 04:38 PM

OK, I'm planning to give this AstroDMx a try since it works out of the box, I still have a couple questions about it though.

On mine (sorry about all the commented out crap):

----------------------------------------------
/*

I found AstroDMx and quit working on this (for now) about 2/1/2023

Maybe this is generating images until the 10 seconds is up, when there's no
error.


After dem3 I start seeding out images of odd sizes and attaching times to good
ones.

Working, but 640x480 (sort of) 16 bit color. I see in the output:
UncompressedFormat(2)
bits per pixel: 16
FrameDescriptor(2)
size: 3264x2448 (right)

There are lots of others, this would do.
.....................

This is a playground, it can be changed.

copied from the web page at
file:///var/www/html/apiref/index.html

Also see https://libuvc.github.io/libuvc/

*/

#include "libuvc/libuvc.h"
#include <stdio.h>
#include <time.h>
#include <unistd.h> // for sleep
//#include "/usr/programs/c/libuvc/01-23/libuvc/src/ctrl.c"

// res = uvc_start_streaming(devh, &ctrl, cb, 12345, 0); // called later
// 4 params
// doesn't have to exist?
// guess, we're passing device handle, pointer to something, code block, frame
// number, some zero

// skip for now -->
// res = uvc_start_streaming(NULL,NULL,NULL,NUL,NULL);L


// printf("%05d", zipCode); // leading zero example

int icount = 0; // image count
int hres = 3264; // from spec sheet
int vres = 2448;
int fsize = 0;

// segfaults
void idump(void) { // image dump
char fname[40];\
fname[0] = '\0';
snprintf(fname,40,"%05d.dat",icount);
printf("%s\n",fname);

icount++;

}



// size_t write(int fd, const void *buf, size_t count);
void writefile(uvc_frame_t *inp) {
char fname[40];
int fd;
int bytes=0;
// int fsize = inp->width * inp->height * 3;
snprintf(fname,40,"%05d.data",icount);
printf("writefile writing %s\n",fname);
FILE *opf = fopen(fname,"w");
fd = fileno(opf);
bytes = (int) write(fd,inp->data,fsize);
printf("wrote %i bytes\n",bytes);
fclose(opf);
icount++;

};


// useful stuff in: typedef struct uvc_frame {

/*
What I could do is create a struct/record type then malloc space to store a
new one when one comes along. The size seems to be somewhat random, so just
skip frames that are a different size. Use the sequence numbers and whatever
else is useful. But long term storage will be on sd/hard drive anyway.

I could also just do a gettimeofday and not use the times built into
libuvc.
*/

// use rgb instead of bgr? Done, names not changed

// want UVC_FRAME_FORMAT_RGB or UVC_FRAME_FORMAT_UNCOMPRESSED

/* Confusing but there's uvc_frame and uvc_frame_desc, they have some of the
same fields, or almost. Just almost, see fields.txt. There's width/height and
wWidth/wHeight, that's about the closest to exact.
*/

void cb3(uvc_frame_t *frame, void *ptr) { // callback
int fmt; // test;
int bpl;
uvc_frame_t *bgr;
uvc_error_t ret;
// image time is struct timeval,usec resolution, ok
// struct timeval tim;

// idump();
/* We have access, do a couple things , see
file:///var/www/html/apiref/structuvc__frame__desc.html

Well no,
uvc_frame_t' {aka 'struct uvc_frame'} has no member named 'dwMinBitRate'

We really want uvc_still_frame_desc?

I'm also interested in the times in
file:///var/www/html/apiref/structuvc__frame.html for timeofday of frame
capture related to how I offset copies. That's in uvc_frame Struct Reference

*/
// printf("Min bit rate: i\n",frame->dwMinBitRate);
printf("data bytes %i\n",frame->data_bytes); // data bytes 7128576 once
printf("Library owns data: %i\n", frame->library_owns_data); // yes
printf("uvc_frame_format (enum) %i\n", frame->frame_format); // 3
printf("data bytes %i\n",frame->data_bytes); // 15980544 (15 mb)
printf("sequence %u\n",frame->sequence); // frame # (working)
// if (frame->width == hres) {
// break;
// get one of these working!!
// tim = frame->capture_time;
// printf("time: m%s\m",ctime(tim.tv_sec)); // segfaults
printf("time: %s\n",ctime(&frame->capture_time.tv_sec));
// always reads dates in 1969
printf("time_t: %lu\n",frame->capture_time.tv_sec);
// always reads 0 for time_t

printf("time as int %i\n",(int) frame->capture_time.tv_sec); // also 0
/*
Header shows both timespec and timeval structs, misprint?
struct timeval capture_time; and struct timespec capture_time_finished;
*/

/* We'll convert the image from YUV/JPEG to BGR, so allocate space */
bgr = uvc_allocate_frame(frame->width * frame->height * 3);
printf("Image is %i x %i\n",frame->width, frame->height);
if (!bgr) {
printf("unable to allocate bgr frame!");
return;
}

/* Do the BGR conversion */

/*
uvc_error_t uvc_any2bgr(uvc_frame_t *in, uvc_frame_t *out);
*/
printf("buf %i\n",frame->data_bytes); // uuvc buffer size
fsize = frame->data_bytes;
fmt = (int) frame->frame_format;
printf("Data format %i\n",fmt); // it's 3
bpl = frame->step;
printf("Bytes per line %i\n",bpl);
// ret = uvc_any2bgr(frame, bgr);
ret = uvc_any2rgb(frame, bgr); // now RGB, not BGR
if (ret) {
uvc_perror(ret, "uvc_any2bgr error");
uvc_free_frame(bgr);
return;
}
writefile(bgr); // actually rgb of course
uvc_free_frame(bgr);
// } // indent if this works (doesn't)
} // end of cb3



void cb2(uvc_frame_t *frame, void *ptr) { // 2 is old now
int fmt; // test;
int bpl;
uvc_frame_t *bgr;
uvc_error_t ret;
// image time is struct timeval,usec resolution, ok
// struct timeval tim;

// idump();
/* We have access, do a couple things , see
file:///var/www/html/apiref/structuvc__frame__desc.html

Well no,
uvc_frame_t' {aka 'struct uvc_frame'} has no member named 'dwMinBitRate'

We really want uvc_still_frame_desc?

I'm also interested in the times in
file:///var/www/html/apiref/structuvc__frame.html for timeofday of frame
capture related to how I offset copies. That's in uvc_frame Struct Reference

*/
// printf("Min bit rate: i\n",frame->dwMinBitRate);
printf("data bytes %i\n",frame->data_bytes); // data bytes 7128576 once
printf("Library owns data: %i\n", frame->library_owns_data); // yes
printf("uvc_frame_format (enum) %i\n", frame->frame_format); // 3
// printf("data bytes %i\n",frame->data_bytes); // 15980544 (15 mb)
printf("sequence %u\n",frame->sequence); // frame # (working)

// get one of these working!!
// tim = frame->capture_time;
// printf("time: m%s\m",ctime(tim.tv_sec)); // segfaults
printf("time: %s\n",ctime(&frame->capture_time.tv_sec));
// always reads dates in 1969
printf("time_t: %lu\n",frame->capture_time.tv_sec);
// always reads 0 for time_t

printf("time as int %i\n",(int) frame->capture_time.tv_sec); // also 0
/*
Header shows both timespec and timeval structs, misprint?
struct timeval capture_time; and struct timespec capture_time_finished;
*/

/* We'll convert the image from YUV/JPEG to BGR, so allocate space */
bgr = uvc_allocate_frame(frame->width * frame->height * 3);
printf("Image is %i x %i\n",frame->width, frame->height);
if (!bgr) {
printf("unable to allocate bgr frame!");
return;
}

/* Do the BGR conversion */

/*
uvc_error_t uvc_any2bgr(uvc_frame_t *in, uvc_frame_t *out);
*/
printf("buf %i\n",frame->data_bytes); // uuvc buffer size
fsize = frame->data_bytes;
fmt = (int) frame->frame_format;
printf("Data format %i\n",fmt); // it's 3
bpl = frame->step;
printf("Bytes per line %i\n",bpl);
ret = uvc_any2bgr(frame, bgr);
if (ret) {
uvc_perror(ret, "uvc_any2bgr error");
uvc_free_frame(bgr);
return;
}
writefile(bgr);
uvc_free_frame(bgr);
}



int main(int argc, char **argv) {
uvc_context_t *ctx;
uvc_device_t *dev;
uvc_device_handle_t *devh;
uvc_stream_ctrl_t ctrl;
uvc_error_t res;
int rate = 1;
int valid = 0;

/* Initialize a UVC service context. Libuvc will set up its own libusb
* context. Replace NULL with a libusb_context pointer to run libuvc
* from an existing libusb context. */
res = uvc_init(&ctx, NULL);

if (res < 0) {
uvc_perror(res, "uvc_init error in main()");
return res;
}

puts("UVC initialized");

/* Locates the first attached UVC device, stores in dev */
res = uvc_find_device(
ctx, &dev,
0, 0, NULL); /* filter devices: vendor_id, product_id, "serial_num" */

if (res < 0) {
uvc_perror(res, "uvc_find_device failed"); /* no devices found */
} else {
puts("Device found");

/* Try to open the device: requires exclusive access */
res = uvc_open(dev, &devh);

if (res < 0) {
uvc_perror(res, "uvc_open failed"); /* unable to open device */
} else {
puts("Device opened");

/* Print out a message containing all the information that libuvc
* knows about the device */
uvc_print_diag(devh, stderr);
printf("Starting rate loop\n"); // shows ok
while ((rate < 30) && (valid == 0)) {
res = uvc_get_stream_ctrl_format_size(
devh, &ctrl, /* result stored in ctrl */
UVC_FRAME_FORMAT_YUYV,
hres,vres,rate);
printf("stream format returned %i\n",(int) res);
if (res < 0) {
valid = 0;
rate++ ;
} else {
valid = 1;
printf("solution %i\n",rate); // gives 2
}
}

#if (0)
/* Try to negotiate a 640xx480 30 fps YUYV stream profile

What does this actually do? Getting a 2023 version. Look in stream.c,
grep finds a few of them in there. Looking at one:
"Get a negotiated streaming control block for some common parameters."
Going to notes.txt, this looks long.

*/
res = uvc_get_stream_ctrl_format_size(
devh, &ctrl, /* result stored in ctrl */
UVC_FRAME_FORMAT_YUYV, /* YUV 422, aka YUV 4:2:2. try _COMPRESSED */
// UVC_FRAME_FORMAT_RGB, // get_mode failed: Invalid mode (-51)
// UVC_FRAME_FORMAT_BGR, // get_mode failed: Invalid mode (-51)
640, 480, 30 /* width, height, fps */
);
#endif


/* Print out the result */
printf("Start uvc_get_stream_ctrl_format_size results\n");
uvc_print_stream_ctrl(&ctrl, stderr);
printf("End uvc_get_stream_ctrl_format_size results\n");

if (res < 0) {
uvc_perror(res, "get_mode failed"); /* device doesn't provide a matching stream */
} else {
/* Start the video stream. The library will call user function cb:
* cb(frame, (void*) 12345)
*/
// prototype line, no use for all this yet
res = uvc_start_streaming(devh, &ctrl, cb3, 12345, 0);
// skipping for now
res = 0;

if (res < 0) {
// uvc_perror(res, "start_streaming"); /* unable to start stream */
uvc_perror(res,"can't start streaming (res negative)");
} else {
puts("Streaming...");

uvc_set_ae_mode(devh, 1); /* e.g., turn on auto exposure */

sleep(100); /* stream for 10 seconds */

/* End the stream. Blocks until last callback is serviced */
uvc_stop_streaming(devh);
puts("Done streaming.");
}
}

/* Release our handle on the device */
uvc_close(devh);
puts("Device closed");
}

/* Release the device descriptor */
uvc_unref_device(dev);
}

/* Close the UVC context. This closes and cleans up any existing device handles,
* and it closes the libusb context if one was not provided. */
uvc_exit(ctx);
puts("UVC context exited");

return 0;
}


#if (0)
/* This is a version of uvc_get_stream_ctrl_format_size modified to have the
search processes visible.
*/

/** Get a negotiated streaming control block for some common parameters.
* @ingroup streaming
*
* @param[in] devh Device handle
* @param[in,out] ctrl Control block
* @param[in] format_class Type of streaming format
* @param[in] width Desired frame width
* @param[in] height Desired frame height
* @param[in] fps Frame rate, frames per second
*/
uvc_error_t euvc_get_stream_ctrl_format_size( // note e on function name
uvc_device_handle_t *devh,
uvc_stream_ctrl_t *ctrl,
enum uvc_frame_format cf,
int width, int height,
int fps) {
uvc_streaming_interface_t *stream_if;

/* find a matching frame descriptor and interval */
DL_FOREACH(devh->info->stream_ifs, stream_if) {
uvc_format_desc_t *format;
//printf("%s\n",format->

DL_FOREACH(stream_if->format_descs, format) {
uvc_frame_desc_t *frame;

if (!_uvc_frame_format_matches_guid(cf, format->guidFormat))
continue;

DL_FOREACH(format->frame_descs, frame) {
if (frame->wWidth != width || frame->wHeight != height)
continue;

uint32_t *interval;

ctrl->bInterfaceNumber = stream_if->bInterfaceNumber;
UVC_DEBUG("claiming streaming interface %d", stream_if->bInterfaceNumber );
uvc_claim_if(devh, ctrl->bInterfaceNumber);
/* get the max values */
uvc_query_stream_ctrl( devh, ctrl, 1, UVC_GET_MAX);

if (frame->intervals) {
for (interval = frame->intervals; *interval; ++interval) {
// allow a fps rate of zero to mean "accept first rate available"
if (10000000 / *interval == (unsigned int) fps || fps == 0) {

ctrl->bmHint = (1 << 0); /* don't negotiate interval */
ctrl->bFormatIndex = format->bFormatIndex;
ctrl->bFrameIndex = frame->bFrameIndex;
ctrl->dwFrameInterval = *interval;

goto found;
}
}
} else {
uint32_t interval_100ns = 10000000 / fps;
uint32_t interval_offset = interval_100ns - frame->dwMinFrameInterval;

if (interval_100ns >= frame->dwMinFrameInterval
&& interval_100ns <= frame->dwMaxFrameInterval
&& !(interval_offset
&& (interval_offset % frame->dwFrameIntervalStep))) {

ctrl->bmHint = (1 << 0);
ctrl->bFormatIndex = format->bFormatIndex;
ctrl->bFrameIndex = frame->bFrameIndex;
ctrl->dwFrameInterval = interval_100ns;

goto found;
}
}
}
}
}

return UVC_ERROR_INVALID_MODE;

found:
return uvc_probe_stream_ctrl(devh, ctrl);
}
#endif
-----------------------------------------------------------

I had started with a demo program from somewhere and kept tinkering. But the sizes of my output keep varying like
-rw-r--r-- 1 root root 15980544 Feb 2 17:12 00000.data
-rw-r--r-- 1 root root 15980544 Feb 2 17:12 00001.data
-rw-r--r-- 1 root root 15980544 Feb 2 17:12 00002.data
-rw-r--r-- 1 root root 1605480 Feb 2 17:12 00003.data

These are images but just raw 24bpp like you read into Gimp (no compression). I've found what seem to be a few forks of uvc, this is the one I got when I installed Debian's libuvc-doc and followed links within that. Author's name is ktossell but it leads me to https://libuvc.github.io. Such a mess, so many broken versions floating around.

ab1jx 02-02-2023 06:44 PM

Maybe color depth (# of bits) was an issue and after reading https://x-bit-astro-imaging.blogspot...x-capture.html it seems like 8 and 16 bit are both more common than 24. But this was just me, working with my sv205 camera pointed at a light source in the room, I wasn't working with published images. There's not even a telescope connected so no objective lens or mirror and it wasn't even focused.

I have a Raspberry Pi with the 8 inch LCD display this might be a good use for. I can run it on some lithium batteries and mount it on my telescope tripod so it's portable.

And there was nothing in the above article about how he was combining images, but in the Svbony literature they print a nice moon image made from 400 frames https://www.svbony.com/sv205-astronomy-camera I want to be able to do that.
https://www.svbony.com/UploadedMedia...7845084794.jpg

xlfs-0.2 02-02-2023 07:47 PM

The image above is FAR worse than if it were taken by using an iPhone 5c behind very cheap optical (non-digital) telescope with a single frame :)

I am not sure you can capure more light in "a still far field" (stars) as oposed to a near field that is in motio (jittering) family photo held by hand with cell phone - which is what 3 cameras are about solving - per say.

Unless you are trying to improve observation that is jittering due to being hand-held without steady tri-pod, I'm unsure you are going to collect "more light".

Yes, for the moon it moves fast enough that "a short movie" would cause pixels to change and thus (give you a better digital photo). If that is the idea. Otherwise - idk. be a long movie at best.

ab1jx 02-02-2023 07:52 PM

Hmm, stumbled on http://www.qcuiag.org.uk/ Never used an iphone but I did one with my Nikon Coolpix when I got it, maybe 10 years ago. Astrovideo itself is for Windows so there's some fun programming to be done for Linux. http://www.coaa.co.uk/astrovideo.htm

What interested me about this is that integration is just going to give a blur, you need to counteract the earth's rotation and line up frames carefully before overlaying.

xlfs-0.2 02-02-2023 07:55 PM

Product page says:

Support OS Windows, Linux, Raspberry Pi, and Android

Product page says: "records movie and transfers the movie to the devices supported"

I'm unsure why the question is how to grab frames off a devices that sends the whole movie to the Pi.

xlfs-0.2 02-02-2023 08:01 PM

In astronomy there are 2 parts:

1) building observation devices

2) running the observatory

3) consuming / analyzing the observations

It seems you don't need to grab frames off the device but analyze the frame sets it's giving to you.

I really don't think the device can "give you better observations by hacking options through webcam resolution changes"

I think it's set up to give you good observations?

ab1jx 02-02-2023 08:43 PM

Maybe, to me it's like a serial light bucket. What you can't do with a bigger objective lens/mirror you do by combining the light from hundreds of samples. You stand out there in the dark waiting for your eyes to acclimate, here you can have pictures of stars at the full brightness of your monitor. Multiplying is somehow less authentic than combining lots of actual samples.

You grab samples at a rate of maybe 5 per second and at the same time you call the gettimeofday() function so you've got microsecond or better accuracy for each time sample. Some you have to leave out but you have a timestamp for each good frame, so you shift them a certain distance in pixels and add them back together. You can reconstruct stars of fainter magnitudes. It's Hubble in your back yard almost. I'm going to attach it to my modest reflector scope come summer. I grew up with star charts and learning constellations, what Hubble and James Webb have taught us is that there are stars everywhere if you can only see them. Billions and billions to quote Carl Sagan.

ab1jx 02-03-2023 07:08 PM

I had some ideas about specific features I wanted to implement, then I read this article https://astronomyconnect.com/forums/...ronomy-eaa.77/ I didn't specifically see what I wanted to do but it may have gotten called something else, the paper goes way beyond the use of spotting scopes. And I need to invest in a tracking mount for my next step probably. A gallery of what's possible by an amateur is at https://www.nightskiesnetwork.com/#gallery

And the $100 I just spent on my Svbony camera is just the tip of the iceberg, but I've got a house to build. I do like tinkering with writing software, I may play around with Linux libuvc and implement my idea to try this summer. I like AstroDMx a lot though, and it's free. https://www.astrodmx-capture.org.uk/


All times are GMT -5. The time now is 04:41 AM.