r136: This commit was manufactured by cvs2svn to create tag 'hv_1_1_8'.
[cinelerra_cv/mob.git] / hvirtual / cinelerra / vdevicebuz.C
blobad2daa2bd762e4b81e0626f8f439bc3cc450b22a
1 // ALPHA C++ can't compile 64 bit headers
2 #undef _LARGEFILE_SOURCE
3 #undef _LARGEFILE64_SOURCE
4 #undef _FILE_OFFSET_BITS
6 #include "assets.h"
7 #include "bcsignals.h"
8 #include "channel.h"
9 #include "chantables.h"
10 #include "condition.h"
11 #include "file.inc"
12 #include "mutex.h"
13 #include "playbackconfig.h"
14 #include "preferences.h"
15 #include "recordconfig.h"
16 #include "strategies.inc"
17 #include "vdevicebuz.h"
18 #include "vframe.h"
19 #include "videoconfig.h"
20 #include "videodevice.h"
22 #include <errno.h>
23 #include <stdint.h>
24 #include <linux/kernel.h>
25 //#include "videodev2.h"
26 #include <linux/videodev.h>
27 #include <fcntl.h>
28 #include <sys/ioctl.h>
29 #include <sys/mman.h>
30 #include <unistd.h>
34 #define READ_TIMEOUT 5000000
37 VDeviceBUZInput::VDeviceBUZInput(VDeviceBUZ *device)
38  : Thread(1, 1, 0)
40         this->device = device;
41         buffer = 0;
42         buffer_size = 0;
43         total_buffers = 0;
44         current_inbuffer = 0;
45         current_outbuffer = 0;
46         done = 0;
47         output_lock = new Condition(0, "VDeviceBUZInput::output_lock");
48         buffer_lock = new Mutex("VDeviceBUZInput::buffer_lock");
51 VDeviceBUZInput::~VDeviceBUZInput()
53         if(Thread::running())
54         {
55                 done = 1;
56                 Thread::cancel();
57                 Thread::join();
58         }
60         if(buffer)
61         {
62                 for(int i = 0; i < total_buffers; i++)
63                 {
64                         delete [] buffer[i];
65                 }
66                 delete [] buffer;
67                 delete [] buffer_size;
68         }
69         delete output_lock;
70         delete buffer_lock;
73 void VDeviceBUZInput::start()
75 // Create buffers
76         total_buffers = device->device->in_config->capture_length;
77         buffer = new char*[total_buffers];
78         buffer_size = new int[total_buffers];
79         bzero(buffer_size, sizeof(int) * total_buffers);
80         for(int i = 0; i < total_buffers; i++)
81         {
82                 buffer[i] = new char[INPUT_BUFFER_SIZE];
83         }
85         Thread::start();
88 void VDeviceBUZInput::run()
90     struct buz_sync bsync;
92 // Wait for frame
93         while(1)
94         {
95                 Thread::enable_cancel();
96                 if(ioctl(device->jvideo_fd, BUZIOC_SYNC, &bsync) < 0)
97                 {
98                         perror("VDeviceBUZInput::run BUZIOC_SYNC");
99                         if(done) return;
100                         Thread::disable_cancel();
101                 }
102                 else
103                 {
104                         Thread::disable_cancel();
108                         int new_buffer = 0;
109                         buffer_lock->lock("VDeviceBUZInput::run");
110 // Save only if the current buffer is free.
111                         if(!buffer_size[current_inbuffer])
112                         {
113                                 new_buffer = 1;
114 // Copy to input buffer
115                                 memcpy(buffer[current_inbuffer], 
116                                         device->input_buffer + bsync.frame * device->breq.size,
117                                         bsync.length);
119 // Advance input buffer number and decrease semaphore.
120                                 buffer_size[current_inbuffer] = bsync.length;
121                                 increment_counter(&current_inbuffer);
122                         }
124                         buffer_lock->unlock();
126                         if(ioctl(device->jvideo_fd, BUZIOC_QBUF_CAPT, &bsync.frame))
127                                 perror("VDeviceBUZInput::run BUZIOC_QBUF_CAPT");
129                         if(new_buffer) output_lock->unlock();
130                 }
131         }
134 void VDeviceBUZInput::get_buffer(char **ptr, int *size)
136 // Increase semaphore to wait for buffer.
137         int result = output_lock->timed_lock(READ_TIMEOUT, "VDeviceBUZInput::get_buffer");
140 // The driver has its own timeout routine but it doesn't work because
141 // because the tuner lock is unlocked and relocked with no delay.
142 //      int result = 0;
143 //      output_lock->lock("VDeviceBUZInput::get_buffer");
145         if(!result)
146         {
147 // Take over buffer table
148                 buffer_lock->lock("VDeviceBUZInput::get_buffer");
149                 *ptr = buffer[current_outbuffer];
150                 *size = buffer_size[current_outbuffer];
151                 buffer_lock->unlock();
152         }
153         else
154         {
155 //printf("VDeviceBUZInput::get_buffer 1\n");
156                 output_lock->unlock();
157         }
160 void VDeviceBUZInput::put_buffer()
162         buffer_lock->lock("VDeviceBUZInput::put_buffer");
163         buffer_size[current_outbuffer] = 0;
164         buffer_lock->unlock();
165         increment_counter(&current_outbuffer);
168 void VDeviceBUZInput::increment_counter(int *counter)
170         (*counter)++;
171         if(*counter >= total_buffers) *counter = 0;
174 void VDeviceBUZInput::decrement_counter(int *counter)
176         (*counter)--;
177         if(*counter < 0) *counter = total_buffers - 1;
194 VDeviceBUZ::VDeviceBUZ(VideoDevice *device)
195  : VDeviceBase(device)
197         reset_parameters();
198         render_strategies.append(VRENDER_MJPG);
199         tuner_lock = new Mutex("VDeviceBUZ::tuner_lock");
202 VDeviceBUZ::~VDeviceBUZ()
204         close_all();
205         delete tuner_lock;
208 int VDeviceBUZ::reset_parameters()
210         jvideo_fd = 0;
211         input_buffer = 0;
212         output_buffer = 0;
213         frame_buffer = 0;
214         frame_size = 0;
215         frame_allocated = 0;
216         input_error = 0;
217         last_frame_no = 0;
218         temp_frame = 0;
219         user_frame = 0;
220         mjpeg = 0;
221         total_loops = 0;
222         output_number = 0;
223         input_thread = 0;
224         brightness = 32768;
225         hue = 32768;
226         color = 32768;
227         contrast = 32768;
228         whiteness = 32768;
231 int VDeviceBUZ::close_input_core()
233         if(input_thread)
234         {
235                 delete input_thread;
236                 input_thread = 0;
237         }
240         if(device->r)
241         {
242                 if(jvideo_fd) close(jvideo_fd);
243                 jvideo_fd = 0;
244         }
246         if(input_buffer)
247         {
248                 if(input_buffer > 0)
249                         munmap(input_buffer, breq.count * breq.size);
250                 input_buffer = 0;
251         }
254 int VDeviceBUZ::close_output_core()
256 //printf("VDeviceBUZ::close_output_core 1\n");
257         if(device->w)
258         {
259                 int n = -1;
260 //              if(ioctl(jvideo_fd, BUZIOC_QBUF_PLAY, &n) < 0)
261 //                      perror("VDeviceBUZ::close_output_core BUZIOC_QBUF_PLAY");
262                 if(jvideo_fd) close(jvideo_fd);
263                 jvideo_fd = 0;
264         }
265         if(output_buffer)
266         {
267                 if(output_buffer > 0)
268                         munmap(output_buffer, breq.count * breq.size);
269                 output_buffer = 0;
270         }
271         if(temp_frame)
272         {
273                 delete temp_frame;
274                 temp_frame = 0;
275         }
276         if(mjpeg)
277         {
278                 mjpeg_delete(mjpeg);
279                 mjpeg = 0;
280         }
281         if(user_frame)
282         {
283                 delete user_frame;
284                 user_frame = 0;
285         }
286 //printf("VDeviceBUZ::close_output_core 2\n");
287         return 0;
291 int VDeviceBUZ::close_all()
293 //printf("VDeviceBUZ::close_all 1\n");
294         close_input_core();
295 //printf("VDeviceBUZ::close_all 1\n");
296         close_output_core();
297 //printf("VDeviceBUZ::close_all 1\n");
298         if(frame_buffer) delete frame_buffer;
299 //printf("VDeviceBUZ::close_all 1\n");
300         reset_parameters();
301 //printf("VDeviceBUZ::close_all 2\n");
302         return 0;
305 #define COMPOSITE_TEXT "Composite"
306 #define SVIDEO_TEXT "S-Video"
307 #define BUZ_COMPOSITE 0
308 #define BUZ_SVIDEO 1
310 void VDeviceBUZ::get_inputs(ArrayList<char *> *input_sources)
312         char *new_source;
313         input_sources->append(new_source = new char[strlen(COMPOSITE_TEXT) + 1]);
314         strcpy(new_source, COMPOSITE_TEXT);
315         input_sources->append(new_source = new char[strlen(SVIDEO_TEXT) + 1]);
316         strcpy(new_source, SVIDEO_TEXT);
319 int VDeviceBUZ::open_input()
321 // Can't open input until after the channel is set
322         return 0;
325 int VDeviceBUZ::open_output()
327 // Can't open output until after the channel is set
328         return 0;
331 int VDeviceBUZ::set_channel(Channel *channel)
333         if(!channel) return 0;
335         tuner_lock->lock("VDeviceBUZ::set_channel");
337         if(device->r)
338         {
339                 close_input_core();
340                 open_input_core(channel);
341         }
342         else
343         {
344                 close_output_core();
345                 open_output_core(channel);
346         }
348         tuner_lock->unlock();
351         return 0;
354 void VDeviceBUZ::create_channeldb(ArrayList<Channel*> *channeldb)
356         ;
359 int VDeviceBUZ::set_picture(int brightness, 
360                 int hue, 
361                 int color, 
362                 int contrast, 
363                 int whiteness)
365         this->brightness = (int)((float)brightness / 100 * 32767 + 32768);
366         this->hue = (int)((float)hue / 100 * 32767 + 32768);
367         this->color = (int)((float)color / 100 * 32767 + 32768);
368         this->contrast = (int)((float)contrast / 100 * 32767 + 32768);
369         this->whiteness = (int)((float)whiteness / 100 * 32767 + 32768);
372         tuner_lock->lock("VDeviceBUZ::set_picture");
373         if(device->r)
374         {
375                 close_input_core();
376                 open_input_core(0);
377         }
378         else
379         {
380                 close_output_core();
381                 open_output_core(0);
382         }
383         tuner_lock->unlock();
384 // 
385 // 
386 // TRACE("VDeviceBUZ::set_picture 1");
387 //      tuner_lock->lock("VDeviceBUZ::set_picture");
388 // TRACE("VDeviceBUZ::set_picture 2");
389 // 
390 // 
391 // 
392 //      struct video_picture picture_params;
393 // // This call takes a long time in 2.4.22
394 //      if(ioctl(jvideo_fd, VIDIOCGPICT, &picture_params) < 0)
395 //              perror("VDeviceBUZ::set_picture VIDIOCGPICT");
396 //      picture_params.brightness = brightness;
397 //      picture_params.hue = hue;
398 //      picture_params.colour = color;
399 //      picture_params.contrast = contrast;
400 //      picture_params.whiteness = whiteness;
401 // // This call takes a long time in 2.4.22
402 //      if(ioctl(jvideo_fd, VIDIOCSPICT, &picture_params) < 0)
403 //              perror("VDeviceBUZ::set_picture VIDIOCSPICT");
404 //      if(ioctl(jvideo_fd, VIDIOCGPICT, &picture_params) < 0)
405 //              perror("VDeviceBUZ::set_picture VIDIOCGPICT");
406 // 
407 // 
408 // TRACE("VDeviceBUZ::set_picture 10");
409 // 
410 // 
411 //      tuner_lock->unlock();
413         return 0;
416 int VDeviceBUZ::get_norm(int norm)
418         switch(norm)
419         {
420                 case NTSC:          return VIDEO_MODE_NTSC;      break;
421                 case PAL:           return VIDEO_MODE_PAL;       break;
422                 case SECAM:         return VIDEO_MODE_SECAM;     break;
423         }
426 int VDeviceBUZ::read_buffer(VFrame *frame)
428         tuner_lock->lock("VDeviceBUZ::read_buffer");
429         if(!jvideo_fd) open_input_core(0);
431 // Get buffer from thread
432         char *buffer = 0;
433         int buffer_size = 0;
434 // Timer timer;
435 // timer.update();
436         input_thread->get_buffer(&buffer, &buffer_size);
437 //printf("%lld ", timer.get_difference());fflush(stdout);
439         if(buffer)
440         {
441                 frame->allocate_compressed_data(buffer_size);
442                 frame->set_compressed_size(buffer_size);
444 // Transfer fields to frame
445                 if(device->odd_field_first)
446                 {
447                         long field2_offset = mjpeg_get_field2((unsigned char*)buffer, buffer_size);
448                         long field1_len = field2_offset;
449                         long field2_len = buffer_size - field2_offset;
451                         memcpy(frame->get_data(), buffer + field2_offset, field2_len);
452                         memcpy(frame->get_data() + field2_len, buffer, field1_len);
453                 }
454                 else
455                 {
456                         bcopy(buffer, frame->get_data(), buffer_size);
457                 }
459                 input_thread->put_buffer();
460                 tuner_lock->unlock();
461         }
462         else
463         {
464                 tuner_lock->unlock();
465                 Timer timer;
466 //printf("VDeviceBUZ::read_buffer 1\n");
467 // Allow other threads to lock the tuner_lock under NPTL.
468                 timer.delay(100);
469         }
472         return 0;
475 int VDeviceBUZ::open_input_core(Channel *channel)
477         jvideo_fd = open(device->in_config->buz_in_device, O_RDONLY);
479         if(jvideo_fd <= 0)
480         {
481                 fprintf(stderr, "VDeviceBUZ::open_input %s: %s\n", 
482                         device->in_config->buz_in_device,
483                         strerror(errno));
484                 jvideo_fd = 0;
485                 return 1;
486         }
488 // Create input sources
489         get_inputs(&device->input_sources);
491 // Set current input source
492         if(channel)
493         {
494                 for(int i = 0; i < 2; i++)
495                 {
496                         struct video_channel vch;
497                         vch.channel = channel->input;
498                         vch.norm = get_norm(channel->norm);
500 //printf("VDeviceBUZ::open_input_core 2 %d %d\n", vch.channel, vch.norm);
501                         if(ioctl(jvideo_fd, VIDIOCSCHAN, &vch) < 0)
502                                 perror("VDeviceBUZ::open_input_core VIDIOCSCHAN ");
503                 }
504         }
507 // Throw away
508 //     struct video_capability vc;
509 //      if(ioctl(jvideo_fd, VIDIOCGCAP, &vc) < 0)
510 //              perror("VDeviceBUZ::open_input VIDIOCGCAP");
512 // API dependant initialization
513         if(ioctl(jvideo_fd, BUZIOC_G_PARAMS, &bparm) < 0)
514                 perror("VDeviceBUZ::open_input BUZIOC_G_PARAMS");
516         bparm.HorDcm = 1;
517         bparm.VerDcm = 1;
518         bparm.TmpDcm = 1;
519         bparm.field_per_buff = 2;
520         bparm.img_width = device->in_config->w;
521         bparm.img_height = device->in_config->h / bparm.field_per_buff;
522         bparm.img_x = 0;
523         bparm.img_y = 0;
524 //      bparm.APPn = 0;
525 //      bparm.APP_len = 14;
526         bparm.APP_len = 0;
527         bparm.odd_even = 0;
528     bparm.decimation = 0;
529     bparm.quality = device->quality;
530     bzero(bparm.APP_data, sizeof(bparm.APP_data));
532         if(ioctl(jvideo_fd, BUZIOC_S_PARAMS, &bparm) < 0)
533                 perror("VDeviceBUZ::open_input BUZIOC_S_PARAMS");
535 // printf("open_input %d %d %d %d %d %d %d %d %d %d %d %d\n", 
536 //              bparm.HorDcm,
537 //              bparm.VerDcm,
538 //              bparm.TmpDcm,
539 //              bparm.field_per_buff,
540 //              bparm.img_width,
541 //              bparm.img_height,
542 //              bparm.img_x,
543 //              bparm.img_y,
544 //              bparm.APP_len,
545 //              bparm.odd_even,
546 //      bparm.decimation,
547 //      bparm.quality);
549         breq.count = device->in_config->capture_length;
550         breq.size = INPUT_BUFFER_SIZE;
551         if(ioctl(jvideo_fd, BUZIOC_REQBUFS, &breq) < 0)
552                 perror("VDeviceBUZ::open_input BUZIOC_REQBUFS");
554 //printf("open_input %s %d %d %d %d\n", device->in_config->buz_in_device, breq.count, breq.size, bparm.img_width, bparm.img_height);
555         if((input_buffer = (char*)mmap(0, 
556                 breq.count * breq.size, 
557                 PROT_READ, 
558                 MAP_SHARED, 
559                 jvideo_fd, 
560                 0)) <= 0)
561                 perror("VDeviceBUZ::open_input mmap");
564 // Set picture quality
565         struct video_picture picture_params;
566 // This call takes a long time in 2.4.22
567         if(ioctl(jvideo_fd, VIDIOCGPICT, &picture_params) < 0)
568                 perror("VDeviceBUZ::set_picture VIDIOCGPICT");
569         picture_params.brightness = brightness;
570         picture_params.hue = hue;
571         picture_params.colour = color;
572         picture_params.contrast = contrast;
573         picture_params.whiteness = whiteness;
574 // This call takes a long time in 2.4.22
575         if(ioctl(jvideo_fd, VIDIOCSPICT, &picture_params) < 0)
576                 perror("VDeviceBUZ::set_picture VIDIOCSPICT");
577         if(ioctl(jvideo_fd, VIDIOCGPICT, &picture_params) < 0)
578                 perror("VDeviceBUZ::set_picture VIDIOCGPICT");
583 // Start capturing
584         for(int i = 0; i < breq.count; i++)
585         {
586         if(ioctl(jvideo_fd, BUZIOC_QBUF_CAPT, &i) < 0)
587                         perror("VDeviceBUZ::open_input BUZIOC_QBUF_CAPT");
588         }
591         input_thread = new VDeviceBUZInput(this);
592         input_thread->start();
593 //printf("VDeviceBUZ::open_input_core 2\n");
594         return 0;
597 int VDeviceBUZ::open_output_core(Channel *channel)
599 //printf("VDeviceBUZ::open_output 1\n");
600         total_loops = 0;
601         output_number = 0;
602         jvideo_fd = open(device->out_config->buz_out_device, O_RDWR);
603         if(jvideo_fd <= 0)
604         {
605                 perror("VDeviceBUZ::open_output");
606                 return 1;
607         }
610 // Set current input source
611         if(channel)
612         {
613                 struct video_channel vch;
614                 vch.channel = channel->input;
615                 vch.norm = get_norm(channel->norm);
617                 if(ioctl(jvideo_fd, VIDIOCSCHAN, &vch) < 0)
618                         perror("VDeviceBUZ::open_output_core VIDIOCSCHAN ");
619         }
621         breq.count = 10;
622         breq.size = INPUT_BUFFER_SIZE;
623         if(ioctl(jvideo_fd, BUZIOC_REQBUFS, &breq) < 0)
624                 perror("VDeviceBUZ::open_output BUZIOC_REQBUFS");
625         if((output_buffer = (char*)mmap(0, 
626                 breq.count * breq.size, 
627                 PROT_READ | PROT_WRITE, 
628                 MAP_SHARED, 
629                 jvideo_fd, 
630                 0)) <= 0)
631                 perror("VDeviceBUZ::open_output mmap");
633         if(ioctl(jvideo_fd, BUZIOC_G_PARAMS, &bparm) < 0)
634                 perror("VDeviceBUZ::open_output BUZIOC_G_PARAMS");
636         bparm.decimation = 1;
637         bparm.HorDcm = 1;
638         bparm.field_per_buff = 2;
639         bparm.TmpDcm = 1;
640         bparm.VerDcm = 1;
641         bparm.img_width = device->out_w;
642         bparm.img_height = device->out_h / bparm.field_per_buff;
643         bparm.img_x = 0;
644         bparm.img_y = 0;
645         bparm.odd_even = 0;
647         if(ioctl(jvideo_fd, BUZIOC_S_PARAMS, &bparm) < 0)
648                 perror("VDeviceBUZ::open_output BUZIOC_S_PARAMS");
649 //printf("VDeviceBUZ::open_output 2\n");
650         return 0;
655 int VDeviceBUZ::write_buffer(VFrame **frames, EDL *edl)
657 //printf("VDeviceBUZ::write_buffer 1\n");
658         tuner_lock->lock("VDeviceBUZ::write_buffer");
660         if(!jvideo_fd) open_output_core(0);
662         VFrame *ptr = 0;
663         if(frames[0]->get_color_model() != BC_COMPRESSED)
664         {
665                 if(!temp_frame) temp_frame = new VFrame;
666                 if(!mjpeg)
667                 {
668                         mjpeg = mjpeg_new(device->out_w, device->out_h, 2);
669                         mjpeg_set_quality(mjpeg, device->quality);
670                         mjpeg_set_float(mjpeg, 0);
671                 }
672                 ptr = temp_frame;
673                 mjpeg_compress(mjpeg, 
674                         frames[0]->get_rows(), 
675                         frames[0]->get_y(), 
676                         frames[0]->get_u(), 
677                         frames[0]->get_v(),
678                         frames[0]->get_color_model(),
679                         device->cpus);
680                 temp_frame->allocate_compressed_data(mjpeg_output_size(mjpeg));
681                 temp_frame->set_compressed_size(mjpeg_output_size(mjpeg));
682                 bcopy(mjpeg_output_buffer(mjpeg), temp_frame->get_data(), mjpeg_output_size(mjpeg));
683         }
684         else
685                 ptr = frames[0];
687 // Wait for frame to become available
688 // Caused close_output_core to lock up.
689 //      if(total_loops >= 1)
690 //      {
691 //              if(ioctl(jvideo_fd, BUZIOC_SYNC, &output_number) < 0)
692 //                      perror("VDeviceBUZ::write_buffer BUZIOC_SYNC");
693 //      }
695         if(device->out_config->buz_swap_fields)
696         {
697                 long field2_offset = mjpeg_get_field2((unsigned char*)ptr->get_data(), 
698                         ptr->get_compressed_size());
699                 long field2_len = ptr->get_compressed_size() - field2_offset;
700                 memcpy(output_buffer + output_number * breq.size, 
701                         ptr->get_data() + field2_offset, 
702                         field2_len);
703                 memcpy(output_buffer + output_number * breq.size +field2_len,
704                         ptr->get_data(), 
705                         field2_offset);
706         }
707         else
708         {
709                 bcopy(ptr->get_data(), 
710                         output_buffer + output_number * breq.size, 
711                         ptr->get_compressed_size());
712         }
714         if(ioctl(jvideo_fd, BUZIOC_QBUF_PLAY, &output_number) < 0)
715                 perror("VDeviceBUZ::write_buffer BUZIOC_QBUF_PLAY");
717         output_number++;
718         if(output_number >= breq.count)
719         {
720                 output_number = 0;
721                 total_loops++;
722         }
723         tuner_lock->unlock();
724 //printf("VDeviceBUZ::write_buffer 2\n");
726         return 0;
729 void VDeviceBUZ::new_output_buffer(VFrame **outputs,
730         int colormodel)
732 //printf("VDeviceBUZ::new_output_buffer 1 %d\n", colormodel);
733         if(user_frame)
734         {
735                 if(colormodel != user_frame->get_color_model())
736                 {
737                         delete user_frame;
738                         user_frame = 0;
739                 }
740         }
742         if(!user_frame)
743         {
744                 switch(colormodel)
745                 {
746                         case BC_COMPRESSED:
747                                 user_frame = new VFrame;
748                                 break;
749                         default:
750                                 user_frame = new VFrame(0,
751                                         device->out_w,
752                                         device->out_h,
753                                         colormodel,
754                                         -1);
755                                 break;
756                 }
757         }
758         user_frame->set_shm_offset(0);
759         outputs[0] = user_frame;
760 //printf("VDeviceBUZ::new_output_buffer 2\n");
764 ArrayList<int>* VDeviceBUZ::get_render_strategies()
766         return &render_strategies;