framework2
860 строк · 31.6 Кб
1/*
2* ofGstVideoGrabber.cpp
3*
4* Created on: 17/01/2011
5* Author: arturo
6*/
7
8#include "ofGstVideoGrabber.h"
9#include "ofPixels.h"
10
11#include <gst/video/video.h>
12
13#ifdef TARGET_LINUX
14#include <sys/utsname.h>
15#endif
16
17//-------------------------------------------------
18//----------------------------------------- grabber
19//-------------------------------------------------
20
21#ifdef TARGET_LINUX
22
23#define PREFER_RGB_OVER_YUV
24#define PREFER_NON_COMPRESSED
25
26extern "C" {
27#include <libudev.h>
28}
29
30#include <gst/gst.h>
31
32/* for ioctl query */
33#include <fcntl.h>
34#include <unistd.h>
35#include <sys/ioctl.h>
36
37#include <linux/version.h>
38
39#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
40#include <linux/videodev2.h>
41#define VIDIOCGCAP _IOR('v',1,struct video_capability) /* Get capabilities */
42
43struct video_capability
44{
45char name[32];
46int type;
47int channels; /* Num channels */
48int audios; /* Num audio devices */
49int maxwidth; /* Supported width */
50int maxheight; /* And height */
51int minwidth; /* Supported width */
52int minheight; /* And height */
53};
54#else
55#include <linux/videodev.h>
56#endif
57
58
59#endif
60
61using std::string;
62using std::vector;
63
64static void get_video_devices (ofGstCamData & cam_data)
65{
66#ifdef TARGET_LINUX
67int fd, ok;
68
69struct udev * my_udev;
70struct udev_enumerate * enumerate;
71struct udev_list_entry * list;
72struct udev_list_entry * entry;
73
74my_udev = udev_new();
75enumerate = udev_enumerate_new(my_udev);
76udev_enumerate_scan_devices(enumerate);
77list = udev_enumerate_get_list_entry(enumerate);
78
79/*udev_list_entry_foreach(entry,list){
80const char * name = udev_list_entry_get_name(entry);
81struct udev_device * device = udev_device_new_from_syspath(my_udev, name);
82const char * subsystem = udev_device_get_subsystem(device);
83if(strcmp(subsystem,"video4linux")==0){
84num_devices++;
85}
86}*/
87
88ofLogNotice("ofGstVideoGrabber") << "Probing devices with udev...";
89
90/* Initialize webcam structures */
91udev_list_entry_foreach(entry,list){
92const char * name = udev_list_entry_get_name(entry);
93struct udev_device * device = udev_device_new_from_syspath(my_udev, name);
94string subsystem = udev_device_get_subsystem(device);
95
96if(subsystem != "video4linux") continue;
97const char *gstreamer_src, *product_name;
98struct v4l2_capability v2cap;
99struct video_capability v1cap;
100string vendor_id;
101string product_id;
102string serial_id;
103
104const char * dev_node = udev_device_get_devnode(device);
105struct udev_list_entry * properties = udev_device_get_properties_list_entry(device);
106struct udev_list_entry * property;
107udev_list_entry_foreach(property,properties){
108const char * name = udev_list_entry_get_name(property);
109
110if(strcmp(name,"ID_VENDOR_ID")==0){
111vendor_id = udev_list_entry_get_value(property);
112}
113
114if(strcmp(name,"ID_MODEL_ID")==0){
115product_id = udev_list_entry_get_value(property);
116}
117
118if(strcmp(name,"ID_SERIAL")==0){
119serial_id = udev_list_entry_get_value(property);;
120}
121
122}
123
124
125ofLogNotice("ofGstVideoGrabber") << "Found device " << vendor_id << ":" << product_id << ", getting capabilities...";
126
127/* vbi devices support capture capability too, but cannot be used,
128* so detect them by device name */
129if (strstr (dev_node, "vbi"))
130{
131ofLogWarning("ofGstVideoGrabber") << "Skipping vbi device: " << dev_node;
132continue;
133}
134
135
136if ((fd = open (dev_node, O_RDONLY | O_NONBLOCK)) < 0)
137{
138ofLogWarning("ofGstVideoGrabber") << "Failed to open " << dev_node << " " << strerror (errno);
139continue;
140}
141
142ok = ioctl (fd, VIDIOC_QUERYCAP, &v2cap);
143if (ok < 0)
144{
145ok = ioctl (fd, VIDIOCGCAP, &v1cap);
146if (ok < 0)
147{
148ofLogWarning("ofGstVideoGrabber") << "Error while probing v4l capabilities for "
149<< dev_node << " " << strerror (errno);
150close (fd);
151continue;
152}
153ofLogNotice("ofGstVideoGrabber") << "Detected v4l device: " << v1cap.name;
154ofLogNotice("ofGstVideoGrabber") << "device type: " << v1cap.type;
155gstreamer_src = "v4lsrc";
156product_name = v1cap.name;
157}
158else
159{
160guint cap = v2cap.capabilities;
161ofLogNotice("ofGstVideoGrabber") << "detected v4l2 device: " << v2cap.card;
162ofLogNotice("ofGstVideoGrabber") << "driver: " << v2cap.driver << ", version: " << v2cap.version;
163/* g_print ("Bus info: %s\n", v2cap.bus_info); */ /* Doesn't seem anything useful */
164ofLogNotice("ofGstVideoGrabber","Capabilities: 0x%08X", v2cap.capabilities);
165/* Only consider this device, if
166* 1. it has 'Video Capture' capability and
167* 2. if it also has the 'Device Capabilities' then the actual device has
168* the 'Video Capture' capability too */
169if (!(cap & V4L2_CAP_VIDEO_CAPTURE)
170|| (cap & V4L2_CAP_DEVICE_CAPS && !(v2cap.device_caps & V4L2_CAP_VIDEO_CAPTURE))){
171ofLogNotice() << "device " << dev_node
172<< " seems to not have the capture capability, (radio tuner/metadata device?)";
173ofLogNotice() << "removing it from device list";
174close (fd);
175continue;
176}
177gstreamer_src = "v4l2src";
178product_name = (char *) v2cap.card;
179}
180
181
182ofGstDevice gst_device;
183gst_device.video_device = dev_node;
184gst_device.gstreamer_src = gstreamer_src;
185gst_device.product_name = product_name;
186gst_device.serial_id = serial_id;
187cam_data.webcam_devices.push_back(gst_device);
188/*cam_data.webcam_devices[cam_data.num_webcam_devices].video_device = dev_node;
189cam_data.webcam_devices[cam_data.num_webcam_devices].gstreamer_src = gstreamer_src;
190cam_data.webcam_devices[cam_data.num_webcam_devices].product_name = product_name;
191cam_data.webcam_devices[cam_data.num_webcam_devices].num_video_formats = 0;
192cam_data.webcam_devices[cam_data.num_webcam_devices].supported_resolutions =
193g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
194cam_data.num_webcam_devices++;*/
195
196close (fd);
197}
198
199cam_data.bInited=true;
200#endif
201}
202
203
204static void get_supported_framerates (ofGstVideoFormat &video_format, GstStructure &structure)
205{
206const GValue *framerates;
207ofGstFramerate framerate;
208framerates = gst_structure_get_value (&structure, "framerate");
209if (GST_VALUE_HOLDS_FRACTION (framerates)){
210framerate.numerator = gst_value_get_fraction_numerator (framerates);
211framerate.denominator = gst_value_get_fraction_denominator (framerates);
212video_format.framerates.push_back(framerate);
213ofLog(OF_LOG_VERBOSE,"%d/%d ", framerate.numerator,
214framerate.denominator);
215}else if (GST_VALUE_HOLDS_LIST (framerates)){
216int num_framerates = gst_value_list_get_size (framerates);
217for (int i = 0; i < num_framerates; i++){
218const GValue *value = gst_value_list_get_value (framerates, i);
219framerate.numerator = gst_value_get_fraction_numerator (value);
220framerate.denominator = gst_value_get_fraction_denominator (value);
221video_format.framerates.push_back(framerate);
222ofLog(OF_LOG_VERBOSE,"%d/%d ", framerate.numerator,
223framerate.denominator);
224}
225}else if (GST_VALUE_HOLDS_FRACTION_RANGE (framerates)){
226int numerator_min, denominator_min, numerator_max, denominator_max;
227const GValue *fraction_range_min;
228const GValue *fraction_range_max;
229
230fraction_range_min = gst_value_get_fraction_range_min (framerates);
231numerator_min = gst_value_get_fraction_numerator (fraction_range_min);
232denominator_min = gst_value_get_fraction_denominator (fraction_range_min);
233
234fraction_range_max = gst_value_get_fraction_range_max (framerates);
235numerator_max = gst_value_get_fraction_numerator (fraction_range_max);
236denominator_max = gst_value_get_fraction_denominator (fraction_range_max);
237
238ofLogVerbose("ofGstVideoGrabber") << "get_supported_framerates(): from "
239<< numerator_min << "/" << denominator_max
240<< " to " << numerator_max << "/" << denominator_min;
241if(denominator_max==1 && numerator_max>1000000){
242// workaround for #4647 where some camera seems to
243// return a really high value for num_max crashing the app
244numerator_max = 1000;
245}
246for (int i = numerator_min; i <= numerator_max; i++){
247for (int j = denominator_min; j <= denominator_max; j++){
248framerate.numerator = i;
249framerate.denominator = j;
250video_format.framerates.push_back(framerate);
251}
252}
253}else{
254ofLogVerbose("ofGstVideoGrabber") << "get_supported_framerates(): unknown GValue type "
255<< G_VALUE_TYPE_NAME (framerates) << " for framerates";
256}
257}
258
259static void find_framerate (ofGstVideoFormat &format, int desired_framerate = -1)
260{
261int framerate_numerator = 1;
262int framerate_denominator = 1;
263float framerate = -1;
264float prevFramerate = -1;
265// find nearest to desired framerate
266if(desired_framerate!=-1){
267float diff = 9999;
268for(unsigned i=0; i<format.framerates.size(); i++){
269framerate = (float)format.framerates[i].numerator / (float)format.framerates[i].denominator;
270if( fabs((float)desired_framerate - framerate) < diff){
271diff = fabs((float)desired_framerate - framerate );
272framerate_numerator = format.framerates[i].numerator;
273framerate_denominator = format.framerates[i].denominator;
274}
275}
276// find fastest
277}else{
278for (unsigned i = 0; i < format.framerates.size(); i++){
279prevFramerate = framerate;
280framerate = (float)format.framerates[i].numerator / (float)format.framerates[i].denominator;
281if (framerate > prevFramerate ){
282framerate_numerator = format.framerates[i].numerator;
283framerate_denominator = format.framerates[i].denominator;
284}
285}
286}
287
288format.choosen_framerate.numerator = framerate_numerator;
289format.choosen_framerate.denominator = framerate_denominator;
290}
291
292static int find_resolution(ofGstDevice &webcam_device, int width, int height){
293for(unsigned i=0; i<webcam_device.video_formats.size(); i++){
294if(webcam_device.video_formats[i].width == width && webcam_device.video_formats[i].height== height)
295return i;
296}
297return -1;
298}
299
300
301#if GST_VERSION_MAJOR==0
302static void add_video_format (ofGstDevice &webcam_device,
303ofGstVideoFormat &video_format, GstStructure &format_structure, int desired_framerate, ofPixelFormat desiredPixelFormat)
304{
305
306ofLogVerbose("ofGstVideoGrabber") << "add_video_format(): " << video_format.mimetype.c_str()
307<< " " << video_format.width << "x" << video_format.height << " framerates:";
308get_supported_framerates (video_format, format_structure);
309find_framerate (video_format, desired_framerate);
310
311int i = find_resolution(webcam_device,video_format.width, video_format.height);
312
313if (i!=-1) { // Resolution already added ?
314float new_framerate = (float)video_format.choosen_framerate.numerator /
315video_format.choosen_framerate.denominator;
316float curr_framerate = (float)webcam_device.video_formats[i].choosen_framerate.numerator /
317webcam_device.video_formats[i].choosen_framerate.denominator;
318if (desired_framerate == -1){
319if(new_framerate > curr_framerate) {
320ofLogVerbose("ofGstVideoGrabber") << "add_video_format(): higher framerate replacing existing format";
321webcam_device.video_formats[i] = video_format;
322#ifdef PREFER_NON_COMPRESSED
323}else if(webcam_device.video_formats[i].mimetype != "video/x-raw-yuv"
324&& webcam_device.video_formats[i].mimetype != "video/x-raw-rgb"
325&& ( video_format.mimetype == "video/x-raw-yuv" || video_format.mimetype == "video/x-raw-rgb" )
326&& new_framerate == curr_framerate){
327ofLogVerbose("ofGstVideoGrabber") << "add_video_format(): non compressed format with same framerate, replacing existing format";
328webcam_device.video_formats[i] = video_format;
329#else
330}else if((webcam_device.video_formats[i].mimetype == "video/x-raw-yuv"
331|| webcam_device.video_formats[i].mimetype == "video/x-raw-rgb")
332&& ( video_format.mimetype != "video/x-raw-yuv" && video_format.mimetype != "video/x-raw-rgb" )
333&& new_framerate == curr_framerate){
334ofLogVerbose("ofGstVideoGrabber") << "add_video_format(): non compressed format with same framerate, replacing existing format";
335webcam_device.video_formats[i] = video_format;
336#endif
337
338#ifdef PREFER_RGB_OVER_YUV
339}else if(webcam_device.video_formats[i].mimetype == "video/x-raw-yuv"
340&& video_format.mimetype == "video/x-raw-rgb"
341&& new_framerate == curr_framerate){
342ofLogVerbose("ofGstVideoGrabber") << "add_video_format(): rgb format with same framerate as yuv, replacing existing format";
343webcam_device.video_formats[i] = video_format;
344#else
345}else if(webcam_device.video_formats[i].mimetype == "video/x-raw-rgb"
346&& video_format.mimetype == "video/x-raw-yuv"
347&& new_framerate == curr_framerate){
348ofLogVerbose("ofGstVideoGrabber") << "add_video_format(): rgb format with same framerate as yuv, replacing existing format";
349webcam_device.video_formats[i] = video_format;
350#endif
351}else{
352ofLog(OF_LOG_VERBOSE,"already added, skipping\n");
353}
354}else{
355if(fabs(new_framerate - desired_framerate) < fabs(curr_framerate - desired_framerate) ){
356ofLog(OF_LOG_VERBOSE,"more similar framerate replacing existing format\n");
357webcam_device.video_formats[i] = video_format;
358#ifdef PREFER_NON_COMPRESSED
359}else if(webcam_device.video_formats[i].mimetype != "video/x-raw-yuv"
360&& webcam_device.video_formats[i].mimetype != "video/x-raw-rgb"
361&& ( video_format.mimetype == "video/x-raw-yuv" || video_format.mimetype == "video/x-raw-rgb" )
362&& new_framerate == curr_framerate){
363ofLogVerbose("ofGstVideoGrabber") << "add_video_format(): non compressed format with same framerate, replacing existing format";
364webcam_device.video_formats[i] = video_format;
365#else
366}else if((webcam_device.video_formats[i].mimetype == "video/x-raw-yuv"
367|| webcam_device.video_formats[i].mimetype == "video/x-raw-rgb")
368&& ( video_format.mimetype != "video/x-raw-yuv" && video_format.mimetype != "video/x-raw-rgb" )
369&& new_framerate == curr_framerate){
370ofLogVerbose("ofGstVideoGrabber") << "add_video_format(): non compressed format with same framerate, replacing existing format";
371webcam_device.video_formats[i] = video_format;
372#endif
373#ifdef PREFER_RGB_OVER_YUV
374}else if(webcam_device.video_formats[i].mimetype == "video/x-raw-yuv"
375&& video_format.mimetype == "video/x-raw-rgb"
376&& new_framerate == curr_framerate){
377ofLogVerbose("ofGstVideoGrabber") << "add_video_format(): rgb format with same framerate as yuv, replacing existing format";
378webcam_device.video_formats[i] = video_format;
379#else
380}else if(webcam_device.video_formats[i].mimetype == "video/x-raw-rgb"
381&& video_format.mimetype == "video/x-raw-yuv"
382&& new_framerate == curr_framerate){
383ofLogVerbose("ofGstVideoGrabber") << "add_video_format(): rgb format with same framerate as yuv, replacing existing format";
384webcam_device.video_formats[i] = video_format;
385#endif
386}else{
387ofLogVerbose("ofGstVideoGrabber") << "add_video_format(): already added, skipping";
388}
389}
390
391return;
392}
393
394webcam_device.video_formats.push_back(video_format);
395}
396#else
397static void add_video_format (ofGstDevice &webcam_device,
398ofGstVideoFormat &video_format, GstStructure &format_structure, int desired_framerate, ofPixelFormat desiredPixelFormat)
399{
400
401ofLogVerbose("ofGstVideoGrabber") << "add_video_format(): "
402<< video_format.mimetype << " " << video_format.format_name
403<< video_format.width << "x" << video_format.height << " "
404<< "videoformat: " << gst_video_format_from_string(video_format.format_name.c_str())
405<< " framerates: ";
406get_supported_framerates (video_format, format_structure);
407find_framerate (video_format, desired_framerate);
408
409int i = find_resolution(webcam_device,video_format.width, video_format.height);
410
411if (i!=-1) { // Resolution already added ?
412float new_framerate = (float)video_format.choosen_framerate.numerator /
413video_format.choosen_framerate.denominator;
414float curr_framerate = (float)webcam_device.video_formats[i].choosen_framerate.numerator /
415webcam_device.video_formats[i].choosen_framerate.denominator;
416if (desired_framerate == -1){
417// choose faster
418if(new_framerate > curr_framerate) {
419ofLogVerbose("ofGstVideoGrabber") << "add_video_format(): higher framerate replacing existing format";
420webcam_device.video_formats[i] = video_format;
421
422}
423}else{
424if(fabs(new_framerate - desired_framerate) < fabs(curr_framerate - desired_framerate) ){
425ofLogVerbose("ofGstVideoGrabber") << "add_video_format(): more similar framerate replacing existing format";
426webcam_device.video_formats[i] = video_format;
427}else{
428ofLogVerbose("ofGstVideoGrabber") << "add_video_format(): already added, skipping";
429}
430}
431
432// with same fps choose non_compressed over compressed
433if((gst_video_format_from_string(webcam_device.video_formats[i].format_name.c_str()) == GST_VIDEO_FORMAT_ENCODED
434|| gst_video_format_from_string(webcam_device.video_formats[i].format_name.c_str()) == GST_VIDEO_FORMAT_UNKNOWN)
435&& ( gst_video_format_from_string(video_format.format_name.c_str()) != GST_VIDEO_FORMAT_ENCODED )
436&& ( gst_video_format_from_string(video_format.format_name.c_str()) != GST_VIDEO_FORMAT_UNKNOWN )
437&& new_framerate == curr_framerate){
438ofLogVerbose("ofGstVideoGrabber") << "add_video_format(): non compressed format with same framerate, replacing existing format";
439webcam_device.video_formats[i] = video_format;
440}
441
442// with same fps choose desiredPixelFormat over other formats to avoid colorspace compression
443else if(gst_video_format_from_string(webcam_device.video_formats[i].format_name.c_str()) != ofGstVideoUtils::getGstFormat(desiredPixelFormat)
444&& gst_video_format_from_string(video_format.format_name.c_str()) == ofGstVideoUtils::getGstFormat(desiredPixelFormat)
445&& new_framerate == curr_framerate){
446ofLogVerbose("ofGstVideoGrabber") << "add_video_format(): " << webcam_device.video_formats[i].format_name << " format with same framerate as other format, replacing existing format";
447webcam_device.video_formats[i] = video_format;
448
449}
450
451else{
452ofLogVerbose("ofGstVideoGrabber") << "add_video_format(): already added, skipping";
453}
454
455return;
456}
457
458webcam_device.video_formats.push_back(video_format);
459}
460#endif
461
462// TODO: gets formats for cameras, when a format returns a range it gets
463// in steps /2 and *2 from min to max and max to min, for format7 it should be free to get any size
464static void get_supported_video_formats (ofGstDevice &webcam_device, GstCaps &caps, int desired_framerate, ofPixelFormat desiredPixelFormat)
465{
466
467int num_structures;
468
469num_structures = gst_caps_get_size (&caps);
470for (int i = 0; i < num_structures; i++){
471GstStructure *structure;
472const GValue *width, *height;
473structure = gst_caps_get_structure (&caps, i);
474
475width = gst_structure_get_value (structure, "width");
476height = gst_structure_get_value (structure, "height");
477
478if (G_VALUE_HOLDS_INT (width)){
479ofGstVideoFormat video_format;
480
481video_format.mimetype = gst_structure_get_name (structure);
482gst_structure_get_int (structure, "width", &(video_format.width));
483gst_structure_get_int (structure, "height", &(video_format.height));
484#if GST_VERSION_MAJOR==1
485if(gst_structure_get_string(structure,"format"))
486video_format.format_name = gst_structure_get_string(structure,"format");
487#endif
488//cout << gst_structure_to_string(structure) << endl;;
489add_video_format(webcam_device, video_format, *structure, desired_framerate, desiredPixelFormat);
490}else if (GST_VALUE_HOLDS_INT_RANGE (width)){
491int min_width, max_width, min_height, max_height;
492int cur_width, cur_height;
493
494min_width = gst_value_get_int_range_min (width);
495max_width = gst_value_get_int_range_max (width);
496min_height = gst_value_get_int_range_min (height);
497max_height = gst_value_get_int_range_max (height);
498
499cur_width = min_width;
500cur_height = min_height;
501while (cur_width <= max_width && cur_height <= max_height){
502ofGstVideoFormat video_format;
503
504video_format.mimetype = gst_structure_get_name (structure);
505video_format.width = cur_width;
506video_format.height = cur_height;
507#if GST_VERSION_MAJOR==1
508if(gst_structure_get_string(structure,"format"))
509video_format.format_name = gst_structure_get_string(structure,"format");
510#endif
511add_video_format(webcam_device, video_format, *structure, desired_framerate, desiredPixelFormat);
512cur_width *= 2;
513cur_height *= 2;
514}
515
516cur_width = max_width;
517cur_height = max_height;
518while (cur_width > min_width && cur_height > min_height){
519ofGstVideoFormat video_format;
520
521video_format.mimetype = gst_structure_get_name (structure);
522video_format.width = cur_width;
523video_format.height = cur_height;
524#if GST_VERSION_MAJOR==1
525if(gst_structure_get_string(structure,"format"))
526video_format.format_name = gst_structure_get_string(structure,"format");
527#endif
528add_video_format(webcam_device, video_format, *structure, desired_framerate, desiredPixelFormat);
529cur_width /= 2;
530cur_height /= 2;
531}
532}else{
533ofLog(OF_LOG_ERROR, "unknown GValue type %s, for resolution width", G_VALUE_TYPE_NAME (width));
534}
535}
536}
537
538static void get_device_data (ofGstDevice &webcam_device, int desired_framerate, ofPixelFormat desiredPixelFormat)
539{
540string pipeline_desc = webcam_device.gstreamer_src + " name=source device=" +
541webcam_device.video_device + " ! fakesink";
542
543GError * err = NULL;
544GstElement * pipeline = gst_parse_launch (pipeline_desc.c_str(), &err);
545if ((pipeline == NULL) || (err != NULL)){
546if (err){
547ofLog(OF_LOG_ERROR, "ofGstUtils: error getting device data: %s", err->message);
548g_error_free (err);
549}else{
550ofLog(OF_LOG_ERROR, "ofGstUtils: error getting device data, cannot get pipeline");
551}
552if(pipeline)
553gst_object_unref (pipeline);
554return;
555}
556
557// TODO: try to lower seconds,
558// Start the pipeline and wait for max. 10 seconds for it to start up
559gst_element_set_state (pipeline, GST_STATE_READY);
560GstStateChangeReturn ret = gst_element_get_state (pipeline, NULL, NULL, 10 * GST_SECOND);
561
562// Check if any error messages were posted on the bus
563GstBus * bus = gst_element_get_bus (pipeline);
564GstMessage * msg = gst_bus_poll (bus, GST_MESSAGE_ERROR, 0);
565gst_object_unref (bus);
566
567if ((msg == NULL) && (ret == GST_STATE_CHANGE_SUCCESS)){
568
569GstElement *src = gst_bin_get_by_name (GST_BIN (pipeline), "source");
570char *name;
571g_object_get (G_OBJECT (src), "device-name", &name, (void*)NULL);
572
573ofLog(OF_LOG_VERBOSE, "Device: %s (%s)\n", name==NULL?"":name, webcam_device.video_device.c_str());
574GstPad *pad = gst_element_get_static_pad (src, "src");
575GstCaps *caps = gst_pad_get_allowed_caps (pad);
576gst_object_unref (pad);
577
578get_supported_video_formats (webcam_device, *caps, desired_framerate, desiredPixelFormat);
579
580gst_caps_unref (caps);
581gst_object_unref(src);
582}else if(msg){
583gchar *debug;
584gst_message_parse_error(msg, &err, &debug);
585
586ofLog(OF_LOG_ERROR, "ofGstUtils: error getting device data; module %s reported: %s",
587gst_element_get_name(GST_MESSAGE_SRC (msg)), err->message);
588
589g_error_free(err);
590g_free(debug);
591}
592gst_element_set_state (pipeline, GST_STATE_NULL);
593ret = gst_element_get_state (pipeline, NULL, NULL, 10 * GST_SECOND);
594gst_object_unref (pipeline);
595
596}
597
598ofGstVideoGrabber::ofGstVideoGrabber(){
599bIsCamera = false;
600camData.bInited = false;
601
602deviceID = 0;
603attemptFramerate = -1;
604internalPixelFormat = OF_PIXELS_RGB;
605}
606
607ofGstVideoGrabber::~ofGstVideoGrabber(){
608close();
609}
610
611bool ofGstVideoGrabber::setPixelFormat(ofPixelFormat pixelFormat){
612internalPixelFormat = pixelFormat;
613return true;
614}
615
616ofPixelFormat ofGstVideoGrabber::getPixelFormat() const{
617if(videoUtils.isInitialized()){
618return videoUtils.getPixelFormat();
619}else{
620return internalPixelFormat;
621}
622}
623
624void ofGstVideoGrabber::setVerbose(bool bVerbose){
625if(bVerbose) ofSetLogLevel("ofGstVideoGrabber", OF_LOG_VERBOSE);
626else ofSetLogLevel("ofGstVideoGrabber",OF_LOG_NOTICE);
627}
628
629bool ofGstVideoGrabber::isInitialized() const{
630return videoUtils.isInitialized();
631}
632
633ofPixelFormat ofPixelFormatFromGstFormat(string format){
634#if GST_VERSION_MAJOR>=1
635switch(gst_video_format_from_string(format.c_str())){
636case GST_VIDEO_FORMAT_RGB: return OF_PIXELS_RGB;
637case GST_VIDEO_FORMAT_RGBA: return OF_PIXELS_RGBA;
638case GST_VIDEO_FORMAT_BGRA: return OF_PIXELS_BGRA;
639case GST_VIDEO_FORMAT_GRAY8: return OF_PIXELS_MONO;
640case GST_VIDEO_FORMAT_RGB16: return OF_PIXELS_RGB565;
641default: return OF_PIXELS_UNKNOWN;
642}
643#else
644ofLogWarning("ofGstVideoGrabber") << "ofPixelFormatFromGstFormat(): only supported for gstreamer 1.0";
645return OF_PIXELS_UNKNOWN;
646#endif
647}
648
649vector<ofVideoDevice> ofGstVideoGrabber::listDevices() const {
650#if GST_VERSION_MAJOR>=1
651if(!camData.bInited) get_video_devices(camData);
652vector<ofVideoDevice> devices(camData.webcam_devices.size());
653for(unsigned i=0; i<camData.webcam_devices.size(); i++){
654devices[i].id = i;
655devices[i].bAvailable = true;
656devices[i].deviceName = camData.webcam_devices[i].product_name;
657devices[i].hardwareName = camData.webcam_devices[i].video_device;
658devices[i].serialID = camData.webcam_devices[i].serial_id;
659devices[i].formats.resize(camData.webcam_devices[i].video_formats.size());
660for(int j=0;j<(int)camData.webcam_devices[i].video_formats.size();j++){
661devices[i].formats[j].pixelFormat = ofPixelFormatFromGstFormat(camData.webcam_devices[i].video_formats[j].format_name);
662devices[i].formats[j].width = camData.webcam_devices[i].video_formats[j].width;
663devices[i].formats[j].height = camData.webcam_devices[i].video_formats[j].height;
664devices[i].formats[j].framerates.resize(camData.webcam_devices[i].video_formats[j].framerates.size());
665for(int k=0;k<(int)camData.webcam_devices[i].video_formats[j].framerates.size();k++){
666devices[i].formats[j].framerates[k] = float(camData.webcam_devices[i].video_formats[j].framerates[k].numerator)/float(camData.webcam_devices[i].video_formats[j].framerates[k].denominator);
667}
668}
669ofLogVerbose("ofGstVideoGrabber") << "listDevices(): device " << i << ": " << camData.webcam_devices[i].video_device << ": " << camData.webcam_devices[i].product_name;
670}
671return devices;
672#else
673ofLogWarning("ofGstVideoGrabber") << "listDevices(): only supported for gstreamer 1.0";
674return vector<ofVideoDevice>();
675#endif
676}
677
678void ofGstVideoGrabber::setDeviceID(int id){
679if(!camData.bInited) get_video_devices(camData);
680if(int(camData.webcam_devices.size())>id){
681deviceID = id;
682}else{
683ofLogWarning("ofGstVideoGrabber") << "setDeviceID(): selected device doesn't exist, selecting device 0";
684}
685}
686
687ofGstVideoFormat & ofGstVideoGrabber::selectFormat(int w, int h, int desired_framerate, ofPixelFormat desiredPixelFormat){
688int minDiff=999999;
689int mostSimilarFormat=0;
690
691get_device_data (camData.webcam_devices[deviceID], desired_framerate, desiredPixelFormat);
692
693for(unsigned i=0; i<camData.webcam_devices[deviceID].video_formats.size(); i++){
694if(camData.webcam_devices[deviceID].video_formats[i].width==w && camData.webcam_devices[deviceID].video_formats[i].height==h){
695mostSimilarFormat = i;
696break;
697}
698int diff = abs(camData.webcam_devices[deviceID].video_formats[i].width + camData.webcam_devices[deviceID].video_formats[i].height - w - h);
699if(diff<minDiff){
700minDiff = diff;
701mostSimilarFormat = i;
702}
703}
704camData.webcam_devices[deviceID].current_format = mostSimilarFormat;
705return camData.webcam_devices[deviceID].video_formats[mostSimilarFormat];
706}
707
708bool ofGstVideoGrabber::setup(int w, int h){
709if(!camData.bInited) get_video_devices(camData);
710
711if(camData.webcam_devices.size()==0){
712ofLogError("ofGstVideoGrabber") << "initGrabber(): no devices found, exiting without initializing";
713return false;
714}
715
716ofGstVideoFormat format;
717if(internalPixelFormat!=OF_PIXELS_NATIVE){
718format = selectFormat(w, h, attemptFramerate, internalPixelFormat);
719ofLogNotice("ofGstVideoGrabber") << "initGrabber(): selected device: " << camData.webcam_devices[deviceID].product_name;
720ofLogNotice("ofGstVideoGrabber") << "initGrabber(): selected format: " << format.width << "x" << format.height
721<< " " << format.mimetype << " " << format.format_name << " framerate: " << format.choosen_framerate.numerator << "/" << format.choosen_framerate.denominator;
722}
723
724bIsCamera = true;
725
726
727#if GST_VERSION_MAJOR==0
728const char * decodebin = "";
729if(format.mimetype == "video/x-raw-bayer")
730decodebin = "! bayer2rgb ";
731else if(format.mimetype != "video/x-raw-yuv" && format.mimetype != "video/x-raw-rgb")
732decodebin = "! decodebin2 ";
733const char * scale = "! ffmpegcolorspace ";
734if( w!=format.width || h!=format.height ) scale = "! ffvideoscale method=2 ";
735
736string format_str_pipeline = "%s name=video_source device=%s ! "
737"%s,width=%d,height=%d,framerate=%d/%d "
738"%s %s ";
739
740gchar* pipeline_string=g_strdup_printf (
741format_str_pipeline.c_str(),
742camData.webcam_devices[deviceID].gstreamer_src.c_str(),
743camData.webcam_devices[deviceID].video_device.c_str(),
744format.mimetype.c_str(),
745format.width,
746format.height,
747format.choosen_framerate.numerator,
748format.choosen_framerate.denominator,
749decodebin, scale);
750#else
751string pipeline_string;
752string format_str_pipeline;
753string fix_v4l2_316;
754#if defined(TARGET_LINUX) && !defined(OF_USE_GST_GL) && GST_VERSION_MAJOR>0 && GST_VERSION_MINOR>2 && GST_VERSION_MINOR<5
755videoUtils.setCopyPixels(true);
756#endif
757if(internalPixelFormat!=OF_PIXELS_NATIVE){
758string decodebin, scale;
759if(format.mimetype == "video/x-bayer"){
760decodebin = "! bayer2rgb ";
761}else if(gst_video_format_from_string(format.format_name.c_str()) == GST_VIDEO_FORMAT_ENCODED || gst_video_format_from_string(format.format_name.c_str()) ==GST_VIDEO_FORMAT_UNKNOWN){
762decodebin = "! decodebin ";
763}
764
765if(format.format_name!=ofGstVideoUtils::getGstFormatName(internalPixelFormat)){
766scale = "! videoconvert ";
767}
768
769if( w!=format.width || h!=format.height ){
770scale = "! videoscale method=2 ";
771}
772
773if(format.format_name==""){
774format_str_pipeline = "%s name=video_source device=%s ! "
775"%s,width=%d,height=%d,framerate=%d/%d "
776"%s %s ";
777
778pipeline_string=g_strdup_printf (
779format_str_pipeline.c_str(),
780camData.webcam_devices[deviceID].gstreamer_src.c_str(),
781camData.webcam_devices[deviceID].video_device.c_str(),
782format.mimetype.c_str(),
783format.width,
784format.height,
785format.choosen_framerate.numerator,
786format.choosen_framerate.denominator,
787decodebin.c_str(), (scale + fix_v4l2_316).c_str());
788}else{
789format_str_pipeline = "%s name=video_source device=%s ! "
790"%s,format=%s,width=%d,height=%d,framerate=%d/%d "
791"%s %s ";
792
793pipeline_string=g_strdup_printf (
794format_str_pipeline.c_str(),
795camData.webcam_devices[deviceID].gstreamer_src.c_str(),
796camData.webcam_devices[deviceID].video_device.c_str(),
797format.mimetype.c_str(),
798format.format_name.c_str(),
799format.width,
800format.height,
801format.choosen_framerate.numerator,
802format.choosen_framerate.denominator,
803decodebin.c_str(), (scale + fix_v4l2_316).c_str());
804}
805}else{
806format_str_pipeline = "v4l2src name=video_source device=/dev/video%d ! video/x-raw,framerate=%d/1 %s";
807pipeline_string=g_strdup_printf (
808format_str_pipeline.c_str(),
809deviceID,attemptFramerate,fix_v4l2_316.c_str());
810
811
812}
813#endif
814
815
816
817return videoUtils.setPipeline(pipeline_string,internalPixelFormat,false,w,h) && videoUtils.startPipeline();
818}
819
820void ofGstVideoGrabber::setDesiredFrameRate(int framerate){
821attemptFramerate = framerate;
822}
823
824ofGstVideoUtils * ofGstVideoGrabber::getGstVideoUtils(){
825return &videoUtils;
826}
827
828
829void ofGstVideoGrabber::update(){
830videoUtils.update();
831}
832
833bool ofGstVideoGrabber::isFrameNew() const {
834return videoUtils.isFrameNew();
835}
836
837
838ofPixels& ofGstVideoGrabber::getPixels(){
839return videoUtils.getPixels();
840}
841
842const ofPixels & ofGstVideoGrabber::getPixels() const {
843return videoUtils.getPixels();
844}
845
846ofTexture * ofGstVideoGrabber::getTexturePtr(){
847return videoUtils.getTexture();
848}
849
850float ofGstVideoGrabber::getHeight() const {
851return videoUtils.getHeight();
852}
853
854float ofGstVideoGrabber::getWidth() const {
855return videoUtils.getWidth();
856}
857
858void ofGstVideoGrabber::close(){
859videoUtils.close();
860}
861