Merge CV, ver=5.1; ops/methods from HV, and interface from CV where possible
[goodguy/history.git] / cinelerra-5.1 / 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(capture_buffer == MAP_FAILED)
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 void 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 }
226
227 int VDeviceV4L::v4l1_set_mute(int muted)
228 {
229         struct video_audio audio;
230
231     if(ioctl(input_fd, VIDIOCGAUDIO, &audio))
232         if(ioctl(input_fd, VIDIOCGAUDIO, &audio) < 0)
233             perror("VDeviceV4L::ioctl VIDIOCGAUDIO");
234
235         audio.volume = 65535;
236         audio.bass = 65535;
237         audio.treble = 65535;
238         if(muted)
239                 audio.flags |= VIDEO_AUDIO_MUTE | VIDEO_AUDIO_VOLUME;
240         else
241                 audio.flags &= ~VIDEO_AUDIO_MUTE;
242
243     if(ioctl(input_fd, VIDIOCSAUDIO, &audio) < 0)
244                 perror("VDeviceV4L::ioctl VIDIOCSAUDIO");
245         return 0;
246 }
247
248
249 int VDeviceV4L::set_cloexec_flag(int desc, int value)
250 {
251         int oldflags = fcntl(desc, F_GETFD, 0);
252         if(oldflags < 0) return oldflags;
253         if(value != 0)
254                 oldflags |= FD_CLOEXEC;
255         else
256                 oldflags &= ~FD_CLOEXEC;
257         return fcntl(desc, F_SETFD, oldflags);
258 }
259
260
261
262
263
264 int VDeviceV4L::get_best_colormodel(Asset *asset)
265 {
266         int result = BC_RGB888;
267
268 // Get best colormodel for hardware acceleration
269
270         result = File::get_best_colormodel(asset, device->in_config->driver);
271
272
273 // Need to get color model before opening device but don't call this
274 // unless you want to open the device either.
275         if(!initialization_complete)
276         {
277                 device_colormodel = translate_colormodel(result);
278                 this->colormodel = result;
279                 v4l_init();
280                 initialization_complete = 1;
281         }
282 // printf("VDeviceV4L::get_best_colormodel %c%c%c%c\n",
283 //      ((char*)&device_colormodel)[0],
284 //      ((char*)&device_colormodel)[1],
285 //      ((char*)&device_colormodel)[2],
286 //      ((char*)&device_colormodel)[3]);
287         return result;
288 }
289
290 unsigned long VDeviceV4L::translate_colormodel(int colormodel)
291 {
292         unsigned long result = 0;
293         switch(colormodel)
294         {
295                 case BC_YUV422:      result = VIDEO_PALETTE_YUV422;      break;
296                 case BC_YUV420P:     result = VIDEO_PALETTE_YUV420P;     break;
297                 case BC_YUV422P:     result = VIDEO_PALETTE_YUV422P;     break;
298                 case BC_YUV411P:     result = VIDEO_PALETTE_YUV411P;     break;
299                 case BC_RGB888:      result = VIDEO_PALETTE_RGB24;       break;
300                 default: result = VIDEO_PALETTE_RGB24; break;
301         }
302 //printf("VDeviceV4L::translate_colormodel %d\n", result);
303         return result;
304 }
305
306 int VDeviceV4L::set_channel(Channel *channel)
307 {
308         return v4l1_set_channel(channel);
309 }
310
311 int VDeviceV4L::v4l1_set_channel(Channel *channel)
312 {
313         struct video_channel channel_struct;
314         struct video_tuner tuner_struct;
315         unsigned long new_freq;
316
317 // Mute changed the input to TV
318 //      set_mute(1);
319
320 //printf("VDeviceV4L::v4l1_set_channel 1 %d\n", channel->input);
321 // Read norm/input defaults
322         channel_struct.channel = channel->input;
323         if(ioctl(input_fd, VIDIOCGCHAN, &channel_struct) < 0)
324                 perror("VDeviceV4L::v4l1_set_channel VIDIOCGCHAN");
325
326 // Set norm/input
327         channel_struct.channel = channel->input;
328         channel_struct.norm = v4l1_get_norm(channel->norm);
329         if(ioctl(input_fd, VIDIOCSCHAN, &channel_struct) < 0)
330                 perror("VDeviceV4L::v4l1_set_channel VIDIOCSCHAN");
331
332         if(channel_struct.flags & VIDEO_VC_TUNER)
333         {
334 // Read tuner defaults
335                 tuner_struct.tuner = channel->input;
336                 if(ioctl(input_fd, VIDIOCGTUNER, &tuner_struct) < 0)
337                         perror("VDeviceV4L::v4l1_set_channel VIDIOCGTUNER");
338
339 // Set tuner
340                 tuner_struct.mode = v4l1_get_norm(channel->norm);
341                 if(ioctl(input_fd, VIDIOCSTUNER, &tuner_struct) < 0)
342                         perror("VDeviceV4L::v4l1_set_channel VIDIOCSTUNER");
343
344                 new_freq = chanlists[channel->freqtable].list[channel->entry].freq;
345                 new_freq = (int)(new_freq * 0.016);
346                 new_freq += channel->fine_tune;
347
348                 if(ioctl(input_fd, VIDIOCSFREQ, &new_freq) < 0)
349                         perror("VDeviceV4L::v4l1_set_channel VIDIOCSFREQ");
350         }
351 //      set_mute(0);
352         return 0;
353 }
354
355 int VDeviceV4L::v4l1_get_norm(int norm)
356 {
357         switch(norm)
358         {
359                 case NTSC:         return VIDEO_MODE_NTSC;         break;
360                 case PAL:          return VIDEO_MODE_PAL;          break;
361                 case SECAM:        return VIDEO_MODE_SECAM;        break;
362         }
363         return 0;
364 }
365
366 int VDeviceV4L::set_picture(PictureConfig *picture)
367 {
368         v4l1_set_picture(picture);
369         return 0;
370 }
371
372
373 int VDeviceV4L::v4l1_set_picture(PictureConfig *picture)
374 {
375         int brightness = (int)((float)picture->brightness / 100 * 32767 + 32768);
376         int hue = (int)((float)picture->hue / 100 * 32767 + 32768);
377         int color = (int)((float)picture->color / 100 * 32767 + 32768);
378         int contrast = (int)((float)picture->contrast / 100 * 32767 + 32768);
379         int whiteness = (int)((float)picture->whiteness / 100 * 32767 + 32768);
380
381         if(ioctl(input_fd, VIDIOCGPICT, &picture_params) < 0)
382                 perror("VDeviceV4L::v4l1_set_picture VIDIOCGPICT");
383         picture_params.brightness = brightness;
384         picture_params.hue = hue;
385         picture_params.colour = color;
386         picture_params.contrast = contrast;
387         picture_params.whiteness = whiteness;
388 // Bogus.  Values are only set in the capture routine.
389         picture_params.depth = 3;
390         picture_params.palette = device_colormodel;
391         if(ioctl(input_fd, VIDIOCSPICT, &picture_params) < 0)
392                 perror("VDeviceV4L::v4l1_set_picture VIDIOCSPICT");
393         if(ioctl(input_fd, VIDIOCGPICT, &picture_params) < 0)
394                 perror("VDeviceV4L::v4l1_set_picture VIDIOCGPICT");
395         return 0;
396 }
397
398
399 int VDeviceV4L::capture_frame(int capture_frame_number)
400 {
401         struct video_mmap params;
402         params.frame = capture_frame_number;
403         params.width = device->in_config->w;
404         params.height = device->in_config->h;
405 // Required to actually set the palette.
406         params.format = device_colormodel;
407 // Tells the driver the buffer is available for writing
408         if(ioctl(input_fd, VIDIOCMCAPTURE, &params) < 0)
409                 perror("VDeviceV4L::capture_frame VIDIOCMCAPTURE");
410         return 0;
411 }
412
413 int VDeviceV4L::wait_v4l_frame()
414 {
415 //printf("VDeviceV4L::wait_v4l_frame 1 %d\n", capture_frame_number);
416         if(ioctl(input_fd, VIDIOCSYNC, &capture_frame_number))
417                 perror("VDeviceV4L::wait_v4l_frame VIDIOCSYNC");
418 //printf("VDeviceV4L::wait_v4l_frame 2 %d\n", capture_frame_number);
419         return 0;
420 }
421
422 int VDeviceV4L::read_v4l_frame(VFrame *frame)
423 {
424         frame_to_vframe(frame, (unsigned char*)capture_buffer + capture_params.offsets[capture_frame_number]);
425         return 0;
426 }
427
428 #ifndef MIN
429 #define MIN(x, y) ((x) < (y) ? (x) : (y))
430 #endif
431
432 int VDeviceV4L::frame_to_vframe(VFrame *frame, unsigned char *input)
433 {
434         int inwidth, inheight;
435         int width, height;
436
437         inwidth = window_params.width;
438         inheight = window_params.height;
439
440         width = MIN(inwidth, frame->get_w());
441         height = MIN(inheight, frame->get_h());
442 //printf("VDeviceV4L::frame_to_vframe %d %d\n", colormodel, frame->get_color_model());
443
444         if(frame->get_color_model() == colormodel)
445         {
446                 switch(frame->get_color_model())
447                 {
448                         case BC_RGB888:
449                         {
450                                 unsigned char *row_in;
451                                 unsigned char *row_out_start, *row_out_end;
452                                 int bytes_per_inrow = inwidth * 3;
453                                 int bytes_per_outrow = frame->get_bytes_per_line();
454                                 unsigned char **rows_out = frame->get_rows();
455
456                                 for(int i = 0; i < frame->get_h(); i++)
457                                 {
458                                         row_in = input + bytes_per_inrow * i;
459                                         row_out_start = rows_out[i];
460                                         row_out_end = row_out_start +
461                                                 MIN(bytes_per_outrow, bytes_per_inrow);
462
463                                         while(row_out_start < row_out_end)
464                                         {
465                                                 *row_out_start++ = row_in[2];
466                                                 *row_out_start++ = row_in[1];
467                                                 *row_out_start++ = row_in[0];
468                                                 row_in += 3;
469                                         }
470                                 }
471                                 break;
472                         }
473
474                         case BC_YUV420P:
475                         case BC_YUV411P:
476                                 memcpy(frame->get_y(), input, width * height);
477                                 memcpy(frame->get_u(), input + width * height, width * height / 4);
478                                 memcpy(frame->get_v(), input + width * height + width * height / 4, width * height / 4);
479                                 break;
480
481                         case BC_YUV422P:
482                                 memcpy(frame->get_y(), input, width * height);
483                                 memcpy(frame->get_u(), input + width * height, width * height / 2);
484                                 memcpy(frame->get_v(), input + width * height + width * height / 2, width * height / 2);
485                                 break;
486
487                         case BC_YUV422:
488                                 memcpy(frame->get_data(),
489                                         input,
490                                         VFrame::calculate_data_size(width,
491                                                 height,
492                                                 -1,
493                                                 frame->get_color_model()));
494                                 break;
495                 }
496         }
497         else
498         {
499                 VFrame *in_frame = new VFrame(input,
500                         -1,
501                         inwidth,
502                         inheight,
503                         colormodel,
504                         -1);
505                 BC_CModels::transfer(frame->get_rows(),
506                         in_frame->get_rows(),
507                         frame->get_y(),
508                         frame->get_u(),
509                         frame->get_v(),
510                         in_frame->get_y(),
511                         in_frame->get_u(),
512                         in_frame->get_v(),
513                         0,
514                         0,
515                         inwidth,
516                         inheight,
517                         0,
518                         0,
519                         frame->get_w(),
520                         frame->get_h(),
521                         colormodel,
522                         frame->get_color_model(),
523                         0,
524                         inwidth,
525                         inheight);
526         }
527         return 0;
528 }
529
530
531
532 int VDeviceV4L::next_frame(int previous_frame)
533 {
534         int result = previous_frame + 1;
535
536         if(result >= MIN(capture_params.frames, device->in_config->capture_length)) result = 0;
537         return result;
538 }
539
540 int VDeviceV4L::read_buffer(VFrame *frame)
541 {
542 SET_TRACE
543         if(shared_memory)
544         {
545 // Read the current frame
546                 if(!got_first_frame) v4l1_start_capture();
547                 wait_v4l_frame();
548                 read_v4l_frame(frame);
549 // Free this frame up for capturing
550                 capture_frame(capture_frame_number);
551 // Advance the frame to capture.
552                 capture_frame_number = next_frame(capture_frame_number);
553         }
554         else
555         {
556                 read(input_fd, capture_buffer, capture_params.size);
557         }
558
559         got_first_frame = 1;
560 SET_TRACE
561         return 0;
562 }
563
564
565
566
567 #endif // HAVE_VIDEO4LINUX
568
569
570
571
572
573