rework android-rmt display, add a few buttons
[goodguy/history.git] / cinelerra-5.0 / cinelerra / vdevicev4l.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  * 
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * 
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  * 
20  */
21
22
23 #ifdef HAVE_VIDEO4LINUX
24
25 // V4L2 is incompatible with large file support
26 // ALPHA C++ can't compile 64 bit headers
27 #undef _FILE_OFFSET_BITS
28 #undef _LARGEFILE_SOURCE
29 #undef _LARGEFILE64_SOURCE
30
31
32 #include "assets.h"
33 #include "bcsignals.h"
34 #include "channel.h"
35 #include "chantables.h"
36 #include "clip.h"
37 #include "file.h"
38 #include "picture.h"
39 #include "preferences.h"
40 #include "recordconfig.h"
41 #include "vdevicev4l.h"
42 #include "vframe.h"
43 #include "videodevice.h"
44
45 #include <unistd.h>
46 #include <sys/ioctl.h>
47 #include <fcntl.h>
48 #include <sys/mman.h>
49 #include <string.h>
50
51 VDeviceV4L::VDeviceV4L(VideoDevice *device)
52  : VDeviceBase(device)
53 {
54         initialize();
55 }
56
57 VDeviceV4L::~VDeviceV4L()
58 {
59 }
60
61 int VDeviceV4L::initialize()
62 {
63         capture_buffer = 0;
64         capture_frame_number = 0;
65         read_frame_number = 0;
66         shared_memory = 0;
67         initialization_complete = 0;
68         return 0;
69 }
70
71 int VDeviceV4L::open_input()
72 {
73         device->channel->use_frequency = 1;
74         device->channel->use_fine = 1;
75         device->channel->use_norm = 1;
76         device->channel->use_input = 1;
77
78
79         device->picture->use_brightness = 1;
80         device->picture->use_contrast = 1;
81         device->picture->use_color = 1;
82         device->picture->use_hue = 1;
83         device->picture->use_whiteness = 1;
84
85         if((input_fd = open(device->in_config->v4l_in_device, O_RDWR)) < 0)
86         {
87                 perror("VDeviceV4L::open_input");
88                 return 1;
89         }
90         else
91         {
92                 v4l1_get_inputs();
93                 close(input_fd);
94         }
95         return 0;
96 }
97
98 int VDeviceV4L::close_all()
99 {
100         close_v4l();
101         return 0;
102 }
103
104 int VDeviceV4L::close_v4l()
105 {
106         unmap_v4l_shmem();
107         if(input_fd != -1) close(input_fd);
108         return 0;
109 }
110
111 int VDeviceV4L::unmap_v4l_shmem()
112 {
113         if(capture_buffer)
114         {
115                 if(shared_memory)
116                         munmap(capture_buffer, capture_params.size);
117                 else
118                         delete capture_buffer;
119                 capture_buffer = 0;
120         }
121         return 0;
122 }
123
124 int VDeviceV4L::v4l_init()
125 {
126         input_fd = open(device->in_config->v4l_in_device, O_RDWR);
127
128         if(input_fd < 0)
129                 perror("VDeviceV4L::v4l_init");
130         else
131         {
132                 set_cloexec_flag(input_fd, 1);
133                 set_mute(0);
134                 if(ioctl(input_fd, VIDIOCGWIN, &window_params) < 0)
135                         perror("VDeviceV4L::v4l_init VIDIOCGWIN");
136                 window_params.x = 0;
137                 window_params.y = 0;
138                 window_params.width = device->in_config->w;
139                 window_params.height = device->in_config->h;
140                 window_params.chromakey = 0;
141                 window_params.flags = 0;
142                 window_params.clipcount = 0;
143                 if(ioctl(input_fd, VIDIOCSWIN, &window_params) < 0)
144                         perror("VDeviceV4L::v4l_init VIDIOCSWIN");
145                 if(ioctl(input_fd, VIDIOCGWIN, &window_params) < 0)
146                         perror("VDeviceV4L::v4l_init VIDIOCGWIN");
147
148                 device->in_config->w = window_params.width;
149                 device->in_config->h = window_params.height;
150
151                 PictureConfig picture(0);
152                 set_picture(&picture);
153
154                 if(ioctl(input_fd, VIDIOCGMBUF, &capture_params) < 0)
155                         perror("VDeviceV4L::v4l_init VIDIOCGMBUF");
156
157                 capture_buffer = (char*)mmap(0, 
158                         capture_params.size, 
159                         PROT_READ|PROT_WRITE, 
160                         MAP_SHARED, 
161                         input_fd, 
162                         0);
163
164                 capture_frame_number = 0;
165
166                 if((long)capture_buffer < 0)
167                 {
168 // Use read instead.
169                         perror("VDeviceV4L::v4l_init mmap");
170                         shared_memory = 0;
171                         capture_buffer = new char[capture_params.size];
172                 }
173                 else
174                 {
175 // Get all frames capturing
176                         shared_memory = 1;
177                 }
178         }
179         got_first_frame = 0;
180         return 0;
181 }
182
183 void VDeviceV4L::v4l1_start_capture()
184 {
185         for(int i = 0; i < MIN(capture_params.frames, device->in_config->capture_length); i++)
186                 capture_frame(i);
187 }
188
189
190
191
192
193
194
195
196 int VDeviceV4L::v4l1_get_inputs()
197 {
198         struct video_channel channel_struct;
199         int i = 0, done = 0;
200
201         while(!done && i < 20)
202         {
203                 channel_struct.channel = i;
204                 if(ioctl(input_fd, VIDIOCGCHAN, &channel_struct) < 0)
205                 {
206 // Finished
207                         done = 1;
208                 }
209                 else
210                 {
211                         Channel *channel = new Channel;
212                         strcpy(channel->device_name, channel_struct.name);
213                         device->input_sources.append(channel);
214                 }
215                 i++;
216         }
217         return 0;
218 }
219
220 int VDeviceV4L::set_mute(int muted)
221 {
222 // Open audio, which obviously is controlled by the video driver.
223 // and apparently resets the input source.
224         v4l1_set_mute(muted);
225         return 0;
226 }
227
228 int VDeviceV4L::v4l1_set_mute(int muted)
229 {
230         struct video_audio audio;
231
232     if(ioctl(input_fd, VIDIOCGAUDIO, &audio))
233         if(ioctl(input_fd, VIDIOCGAUDIO, &audio) < 0)
234             perror("VDeviceV4L::ioctl VIDIOCGAUDIO");
235
236         audio.volume = 65535;
237         audio.bass = 65535;
238         audio.treble = 65535;
239         if(muted)
240                 audio.flags |= VIDEO_AUDIO_MUTE | VIDEO_AUDIO_VOLUME;
241         else
242                 audio.flags &= ~VIDEO_AUDIO_MUTE;
243
244     if(ioctl(input_fd, VIDIOCSAUDIO, &audio) < 0)
245                 perror("VDeviceV4L::ioctl VIDIOCSAUDIO");
246         return 0;
247 }
248
249
250 int VDeviceV4L::set_cloexec_flag(int desc, int value)
251 {
252         int oldflags = fcntl(desc, F_GETFD, 0);
253         if(oldflags < 0) return oldflags;
254         if(value != 0) 
255                 oldflags |= FD_CLOEXEC;
256         else
257                 oldflags &= ~FD_CLOEXEC;
258         return fcntl(desc, F_SETFD, oldflags);
259 }
260
261
262
263
264
265 int VDeviceV4L::get_best_colormodel(Asset *asset)
266 {
267         int result = BC_RGB888;
268
269 // Get best colormodel for hardware acceleration
270
271         result = File::get_best_colormodel(asset, device->in_config->driver);
272
273
274 // Need to get color model before opening device but don't call this
275 // unless you want to open the device either.
276         if(!initialization_complete)
277         {
278                 device_colormodel = translate_colormodel(result);
279                 this->colormodel = result;
280                 v4l_init();
281                 initialization_complete = 1;
282         }
283 // printf("VDeviceV4L::get_best_colormodel %c%c%c%c\n", 
284 //      ((char*)&device_colormodel)[0],
285 //      ((char*)&device_colormodel)[1],
286 //      ((char*)&device_colormodel)[2],
287 //      ((char*)&device_colormodel)[3]);
288         return result;
289 }
290
291 unsigned long VDeviceV4L::translate_colormodel(int colormodel)
292 {
293         unsigned long result = 0;
294         switch(colormodel)
295         {
296                 case BC_YUV422:      result = VIDEO_PALETTE_YUV422;      break;
297                 case BC_YUV420P:     result = VIDEO_PALETTE_YUV420P;     break;
298                 case BC_YUV422P:     result = VIDEO_PALETTE_YUV422P;     break;
299                 case BC_YUV411P:     result = VIDEO_PALETTE_YUV411P;     break;
300                 case BC_RGB888:      result = VIDEO_PALETTE_RGB24;       break;
301                 default: result = VIDEO_PALETTE_RGB24; break;
302         }
303 //printf("VDeviceV4L::translate_colormodel %d\n", result);
304         return result;
305 }
306
307 int VDeviceV4L::set_channel(Channel *channel)
308 {
309         return v4l1_set_channel(channel);
310 }
311
312 int VDeviceV4L::v4l1_set_channel(Channel *channel)
313 {
314         struct video_channel channel_struct;
315         struct video_tuner tuner_struct;
316         unsigned long new_freq;
317
318 // Mute changed the input to TV
319 //      set_mute(1);
320
321 //printf("VDeviceV4L::v4l1_set_channel 1 %d\n", channel->input);
322 // Read norm/input defaults
323         channel_struct.channel = channel->input;
324         if(ioctl(input_fd, VIDIOCGCHAN, &channel_struct) < 0)
325                 perror("VDeviceV4L::v4l1_set_channel VIDIOCGCHAN");
326
327 // Set norm/input
328         channel_struct.channel = channel->input;
329         channel_struct.norm = v4l1_get_norm(channel->norm);
330         if(ioctl(input_fd, VIDIOCSCHAN, &channel_struct) < 0)
331                 perror("VDeviceV4L::v4l1_set_channel VIDIOCSCHAN");
332
333         if(channel_struct.flags & VIDEO_VC_TUNER)
334         {
335 // Read tuner defaults
336                 tuner_struct.tuner = channel->input;
337                 if(ioctl(input_fd, VIDIOCGTUNER, &tuner_struct) < 0)
338                         perror("VDeviceV4L::v4l1_set_channel VIDIOCGTUNER");
339
340 // Set tuner
341                 tuner_struct.mode = v4l1_get_norm(channel->norm);
342                 if(ioctl(input_fd, VIDIOCSTUNER, &tuner_struct) < 0)
343                         perror("VDeviceV4L::v4l1_set_channel VIDIOCSTUNER");
344
345                 new_freq = chanlists[channel->freqtable].list[channel->entry].freq;
346                 new_freq = (int)(new_freq * 0.016);
347                 new_freq += channel->fine_tune;
348
349                 if(ioctl(input_fd, VIDIOCSFREQ, &new_freq) < 0)
350                         perror("VDeviceV4L::v4l1_set_channel VIDIOCSFREQ");
351         }
352 //      set_mute(0);
353         return 0;
354 }
355
356 int VDeviceV4L::v4l1_get_norm(int norm)
357 {
358         switch(norm)
359         {
360                 case NTSC:         return VIDEO_MODE_NTSC;         break;
361                 case PAL:          return VIDEO_MODE_PAL;          break;
362                 case SECAM:        return VIDEO_MODE_SECAM;        break;
363         }
364         return 0;
365 }
366
367 int VDeviceV4L::set_picture(PictureConfig *picture)
368 {
369         v4l1_set_picture(picture);
370         return 0;
371 }
372
373
374 int VDeviceV4L::v4l1_set_picture(PictureConfig *picture)
375 {
376         int brightness = (int)((float)picture->brightness / 100 * 32767 + 32768);
377         int hue = (int)((float)picture->hue / 100 * 32767 + 32768);
378         int color = (int)((float)picture->color / 100 * 32767 + 32768);
379         int contrast = (int)((float)picture->contrast / 100 * 32767 + 32768);
380         int whiteness = (int)((float)picture->whiteness / 100 * 32767 + 32768);
381
382         if(ioctl(input_fd, VIDIOCGPICT, &picture_params) < 0)
383                 perror("VDeviceV4L::v4l1_set_picture VIDIOCGPICT");
384         picture_params.brightness = brightness;
385         picture_params.hue = hue;
386         picture_params.colour = color;
387         picture_params.contrast = contrast;
388         picture_params.whiteness = whiteness;
389 // Bogus.  Values are only set in the capture routine.
390         picture_params.depth = 3;
391         picture_params.palette = device_colormodel;
392         if(ioctl(input_fd, VIDIOCSPICT, &picture_params) < 0)
393                 perror("VDeviceV4L::v4l1_set_picture VIDIOCSPICT");
394         if(ioctl(input_fd, VIDIOCGPICT, &picture_params) < 0)
395                 perror("VDeviceV4L::v4l1_set_picture VIDIOCGPICT");
396         return 0;
397 }
398
399
400 int VDeviceV4L::capture_frame(int capture_frame_number)
401 {
402         struct video_mmap params;
403         params.frame = capture_frame_number;
404         params.width = device->in_config->w;
405         params.height = device->in_config->h;
406 // Required to actually set the palette.
407         params.format = device_colormodel;
408 // Tells the driver the buffer is available for writing
409         if(ioctl(input_fd, VIDIOCMCAPTURE, &params) < 0)
410                 perror("VDeviceV4L::capture_frame VIDIOCMCAPTURE");
411         return 0;
412 }
413
414 int VDeviceV4L::wait_v4l_frame()
415 {
416 //printf("VDeviceV4L::wait_v4l_frame 1 %d\n", capture_frame_number);
417         if(ioctl(input_fd, VIDIOCSYNC, &capture_frame_number))
418                 perror("VDeviceV4L::wait_v4l_frame VIDIOCSYNC");
419 //printf("VDeviceV4L::wait_v4l_frame 2 %d\n", capture_frame_number);
420         return 0;
421 }
422
423 int VDeviceV4L::read_v4l_frame(VFrame *frame)
424 {
425         frame_to_vframe(frame, (unsigned char*)capture_buffer + capture_params.offsets[capture_frame_number]);
426         return 0;
427 }
428
429 #ifndef MIN
430 #define MIN(x, y) ((x) < (y) ? (x) : (y))
431 #endif
432
433 int VDeviceV4L::frame_to_vframe(VFrame *frame, unsigned char *input)
434 {
435         int inwidth, inheight;
436         int width, height;
437
438         inwidth = window_params.width;
439         inheight = window_params.height;
440
441         width = MIN(inwidth, frame->get_w());
442         height = MIN(inheight, frame->get_h());
443 //printf("VDeviceV4L::frame_to_vframe %d %d\n", colormodel, frame->get_color_model());
444
445         if(frame->get_color_model() == colormodel)
446         {
447                 switch(frame->get_color_model())
448                 {
449                         case BC_RGB888:
450                         {
451                                 unsigned char *row_in;
452                                 unsigned char *row_out_start, *row_out_end;
453                                 int bytes_per_inrow = inwidth * 3;
454                                 int bytes_per_outrow = frame->get_bytes_per_line();
455                                 unsigned char **rows_out = frame->get_rows();
456
457                                 for(int i = 0; i < frame->get_h(); i++)
458                                 {
459                                         row_in = input + bytes_per_inrow * i;
460                                         row_out_start = rows_out[i];
461                                         row_out_end = row_out_start + 
462                                                 MIN(bytes_per_outrow, bytes_per_inrow);
463
464                                         while(row_out_start < row_out_end)
465                                         {
466                                                 *row_out_start++ = row_in[2];
467                                                 *row_out_start++ = row_in[1];
468                                                 *row_out_start++ = row_in[0];
469                                                 row_in += 3;
470                                         }
471                                 }
472                                 break;
473                         }
474
475                         case BC_YUV420P:
476                         case BC_YUV411P:
477                                 memcpy(frame->get_y(), input, width * height);
478                                 memcpy(frame->get_u(), input + width * height, width * height / 4);
479                                 memcpy(frame->get_v(), input + width * height + width * height / 4, width * height / 4);
480                                 break;
481
482                         case BC_YUV422P:
483                                 memcpy(frame->get_y(), input, width * height);
484                                 memcpy(frame->get_u(), input + width * height, width * height / 2);
485                                 memcpy(frame->get_v(), input + width * height + width * height / 2, width * height / 2);
486                                 break;
487
488                         case BC_YUV422:
489                                 memcpy(frame->get_data(), 
490                                         input, 
491                                         VFrame::calculate_data_size(width, 
492                                                 height, 
493                                                 -1, 
494                                                 frame->get_color_model()));
495                                 break;
496                 }
497         }
498         else
499         {
500                 VFrame *in_frame = new VFrame(input, 
501                         -1,
502                         inwidth, 
503                         inheight, 
504                         colormodel, 
505                         -1);
506                 BC_CModels::transfer(frame->get_rows(), 
507                         in_frame->get_rows(),
508                         frame->get_y(),
509                         frame->get_u(),
510                         frame->get_v(),
511                         in_frame->get_y(),
512                         in_frame->get_u(),
513                         in_frame->get_v(),
514                         0, 
515                         0, 
516                         inwidth, 
517                         inheight,
518                         0, 
519                         0, 
520                         frame->get_w(), 
521                         frame->get_h(),
522                         colormodel, 
523                         frame->get_color_model(),
524                         0,
525                         inwidth,
526                         inheight);
527         }
528         return 0;
529 }
530
531
532
533 int VDeviceV4L::next_frame(int previous_frame)
534 {
535         int result = previous_frame + 1;
536
537         if(result >= MIN(capture_params.frames, device->in_config->capture_length)) result = 0;
538         return result;
539 }
540
541 int VDeviceV4L::read_buffer(VFrame *frame)
542 {
543 SET_TRACE
544         if(shared_memory)
545         {
546 // Read the current frame
547                 if(!got_first_frame) v4l1_start_capture();
548                 wait_v4l_frame();
549                 read_v4l_frame(frame);
550 // Free this frame up for capturing
551                 capture_frame(capture_frame_number);
552 // Advance the frame to capture.
553                 capture_frame_number = next_frame(capture_frame_number);
554         }
555         else
556         {
557                 read(input_fd, capture_buffer, capture_params.size);
558         }
559
560         got_first_frame = 1;
561 SET_TRACE
562         return 0;
563 }
564
565
566
567
568 #endif // HAVE_VIDEO4LINUX
569
570
571
572
573
574