r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / cinelerra / vdevicebuz.C
blobf6cefa0a50df09eca584bf0e5c4275c5bbeccb0f
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 "channel.h"
8 #include "chantables.h"
9 #include "file.inc"
10 #include "playbackconfig.h"
11 #include "preferences.h"
12 #include "recordconfig.h"
13 #include "strategies.inc"
14 #include "vdevicebuz.h"
15 #include "vframe.h"
16 #include "videoconfig.h"
17 #include "videodevice.h"
19 #include <errno.h>
20 #include <stdint.h>
21 #include <linux/kernel.h>
22 //#include "videodev2.h"
23 #include <linux/videodev.h>
24 #include <fcntl.h>
25 #include <sys/ioctl.h>
26 #include <sys/mman.h>
27 #include <unistd.h>
31 VDeviceBUZInput::VDeviceBUZInput(VDeviceBUZ *device)
32  : Thread(1, 1, 0)
34         this->device = device;
35         buffer = 0;
36         buffer_size = 0;
37         total_buffers = 0;
38         current_inbuffer = 0;
39         current_outbuffer = 0;
40         done = 0;
41         output_lock.lock();
44 VDeviceBUZInput::~VDeviceBUZInput()
46         if(Thread::running())
47         {
48                 done = 1;
49                 Thread::cancel();
50 //printf("VDeviceBUZInput::~VDeviceBUZInput 1\n");
51                 Thread::join();
52 //printf("VDeviceBUZInput::~VDeviceBUZInput 100\n");
53         }
55         if(buffer)
56         {
57                 for(int i = 0; i < total_buffers; i++)
58                 {
59                         delete [] buffer[i];
60                 }
61                 delete [] buffer;
62                 delete [] buffer_size;
63         }
66 void VDeviceBUZInput::start()
68 // Create buffers
69         total_buffers = device->device->in_config->capture_length;
70         buffer = new char*[total_buffers];
71         buffer_size = new int[total_buffers];
72         bzero(buffer_size, sizeof(int) * total_buffers);
73         for(int i = 0; i < total_buffers; i++)
74         {
75                 buffer[i] = new char[INPUT_BUFFER_SIZE];
76         }
78         Thread::start();
81 void VDeviceBUZInput::run()
83     struct buz_sync bsync;
85 // Wait for frame
86         while(1)
87         {
88                 Thread::enable_cancel();
89                 if(ioctl(device->jvideo_fd, BUZIOC_SYNC, &bsync) < 0)
90                 {
91                         perror("VDeviceBUZInput::run BUZIOC_SYNC");
92                         if(done) return;
93                         Thread::disable_cancel();
94                 }
95                 else
96                 {
97                         Thread::disable_cancel();
101                         int new_buffer = 0;
102                         buffer_lock.lock();
103 // Save only if the current buffer is free.
104                         if(!buffer_size[current_inbuffer])
105                         {
106                                 new_buffer = 1;
107 // Copy to input buffer
108                                 memcpy(buffer[current_inbuffer], 
109                                         device->input_buffer + bsync.frame * device->breq.size,
110                                         bsync.length);
112 // Advance input buffer number and decrease semaphore.
113                                 buffer_size[current_inbuffer] = bsync.length;
114                                 increment_counter(&current_inbuffer);
115                         }
117                         buffer_lock.unlock();
119                         if(ioctl(device->jvideo_fd, BUZIOC_QBUF_CAPT, &bsync.frame))
120                                 perror("VDeviceBUZInput::run BUZIOC_QBUF_CAPT");
122                         if(new_buffer) output_lock.unlock();
123                 }
124         }
127 void VDeviceBUZInput::get_buffer(char **ptr, int *size)
129 // Increase semaphore to wait for buffer.
130         output_lock.lock();
132 // Take over buffer table
133         buffer_lock.lock();
134         *ptr = buffer[current_outbuffer];
135         *size = buffer_size[current_outbuffer];
136         buffer_lock.unlock();
139 void VDeviceBUZInput::put_buffer()
141         buffer_lock.lock();
142         buffer_size[current_outbuffer] = 0;
143         buffer_lock.unlock();
144         increment_counter(&current_outbuffer);
147 void VDeviceBUZInput::increment_counter(int *counter)
149         (*counter)++;
150         if(*counter >= total_buffers) *counter = 0;
153 void VDeviceBUZInput::decrement_counter(int *counter)
155         (*counter)--;
156         if(*counter < 0) *counter = total_buffers - 1;
162 VDeviceBUZ::VDeviceBUZ(VideoDevice *device)
163  : VDeviceBase(device)
165         reset_parameters();
166         render_strategies.append(VRENDER_MJPG);
169 VDeviceBUZ::~VDeviceBUZ()
171 //printf("VDeviceBUZ::~VDeviceBUZ 1\n");
172         close_all();
173 //printf("VDeviceBUZ::~VDeviceBUZ 2\n");
176 int VDeviceBUZ::reset_parameters()
178         jvideo_fd = 0;
179         input_buffer = 0;
180         output_buffer = 0;
181         frame_buffer = 0;
182         frame_size = 0;
183         frame_allocated = 0;
184         input_error = 0;
185         last_frame_no = 0;
186         temp_frame = 0;
187         user_frame = 0;
188         mjpeg = 0;
189         total_loops = 0;
190         output_number = 0;
191         input_thread = 0;
194 int VDeviceBUZ::close_input_core()
196 //printf("VDeviceBUZ::close_input_core 1\n");
197         if(input_thread)
198         {
199                 delete input_thread;
200                 input_thread = 0;
201         }
204         if(device->r)
205         {
206                 if(jvideo_fd) close(jvideo_fd);
207                 jvideo_fd = 0;
208         }
210         if(input_buffer)
211         {
212                 if(input_buffer > 0)
213                         munmap(input_buffer, breq.count * breq.size);
214                 input_buffer = 0;
215         }
217 //printf("VDeviceBUZ::close_input_core 2\n");
220 int VDeviceBUZ::close_output_core()
222 //printf("VDeviceBUZ::close_output_core 1\n");
223         if(device->w)
224         {
225                 int n = -1;
226 //              if(ioctl(jvideo_fd, BUZIOC_QBUF_PLAY, &n) < 0)
227 //                      perror("VDeviceBUZ::close_output_core BUZIOC_QBUF_PLAY");
228                 if(jvideo_fd) close(jvideo_fd);
229                 jvideo_fd = 0;
230         }
231         if(output_buffer)
232         {
233                 if(output_buffer > 0)
234                         munmap(output_buffer, breq.count * breq.size);
235                 output_buffer = 0;
236         }
237         if(temp_frame)
238         {
239                 delete temp_frame;
240                 temp_frame = 0;
241         }
242         if(mjpeg)
243         {
244                 mjpeg_delete(mjpeg);
245                 mjpeg = 0;
246         }
247         if(user_frame)
248         {
249                 delete user_frame;
250                 user_frame = 0;
251         }
252 //printf("VDeviceBUZ::close_output_core 2\n");
253         return 0;
257 int VDeviceBUZ::close_all()
259 //printf("VDeviceBUZ::close_all 1\n");
260         close_input_core();
261 //printf("VDeviceBUZ::close_all 1\n");
262         close_output_core();
263 //printf("VDeviceBUZ::close_all 1\n");
264         if(frame_buffer) delete frame_buffer;
265 //printf("VDeviceBUZ::close_all 1\n");
266         reset_parameters();
267 //printf("VDeviceBUZ::close_all 2\n");
268         return 0;
271 #define COMPOSITE_TEXT "Composite"
272 #define SVIDEO_TEXT "S-Video"
273 #define BUZ_COMPOSITE 0
274 #define BUZ_SVIDEO 1
276 void VDeviceBUZ::get_inputs(ArrayList<char *> *input_sources)
278         char *new_source;
279         input_sources->append(new_source = new char[strlen(COMPOSITE_TEXT) + 1]);
280         strcpy(new_source, COMPOSITE_TEXT);
281         input_sources->append(new_source = new char[strlen(SVIDEO_TEXT) + 1]);
282         strcpy(new_source, SVIDEO_TEXT);
285 int VDeviceBUZ::open_input()
287 // Can't open input until after the channel is set
288         return 0;
291 int VDeviceBUZ::open_output()
293 // Can't open output until after the channel is set
294         return 0;
297 int VDeviceBUZ::set_channel(Channel *channel)
299 //printf("VDeviceBUZ::set_channel 1\n");
300         if(!channel) return 0;
302         tuner_lock.lock();
303         if(device->r)
304         {
305                 close_input_core();
306                 open_input_core(channel);
307         }
308         else
309         {
310                 close_output_core();
311                 open_output_core(channel);
312         }
313         tuner_lock.unlock();
314 //printf("VDeviceBUZ::set_channel 2\n");
317         return 0;
320 void VDeviceBUZ::create_channeldb(ArrayList<Channel*> *channeldb)
322         ;
325 int VDeviceBUZ::set_picture(int brightness, 
326                 int hue, 
327                 int color, 
328                 int contrast, 
329                 int whiteness)
331         tuner_lock.lock();
333         struct video_picture picture_params;
334         brightness = (int)((float)brightness / 100 * 32767 + 32768);
335         hue = (int)((float)hue / 100 * 32767 + 32768);
336         color = (int)((float)color / 100 * 32767 + 32768);
337         contrast = (int)((float)contrast / 100 * 32767 + 32768);
338         whiteness = (int)((float)whiteness / 100 * 32767 + 32768);
339         if(ioctl(jvideo_fd, VIDIOCGPICT, &picture_params) < 0)
340                 perror("VDeviceBUZ::set_picture VIDIOCGPICT");
341         picture_params.brightness = brightness;
342         picture_params.hue = hue;
343         picture_params.colour = color;
344         picture_params.contrast = contrast;
345         picture_params.whiteness = whiteness;
346         if(ioctl(jvideo_fd, VIDIOCSPICT, &picture_params) < 0)
347                 perror("VDeviceBUZ::set_picture VIDIOCSPICT");
348         if(ioctl(jvideo_fd, VIDIOCGPICT, &picture_params) < 0)
349                 perror("VDeviceBUZ::set_picture VIDIOCGPICT");
354         tuner_lock.unlock();
355         return 0;
358 int VDeviceBUZ::get_norm(int norm)
360         switch(norm)
361         {
362                 case NTSC:          return VIDEO_MODE_NTSC;      break;
363                 case PAL:           return VIDEO_MODE_PAL;       break;
364                 case SECAM:         return VIDEO_MODE_SECAM;     break;
365         }
368 int VDeviceBUZ::read_buffer(VFrame *frame)
370         tuner_lock.lock();
371         if(!jvideo_fd) open_input_core(0);
373 // Get buffer from thread
374         char *buffer;
375         int buffer_size;
376         input_thread->get_buffer(&buffer, &buffer_size);
378         
379         frame->allocate_compressed_data(buffer_size);
380         frame->set_compressed_size(buffer_size);
382 // Transfer fields to frame
383         if(device->odd_field_first)
384         {
385                 long field2_offset = mjpeg_get_field2((unsigned char*)buffer, buffer_size);
386                 long field1_len = field2_offset;
387                 long field2_len = buffer_size - field2_offset;
389                 memcpy(frame->get_data(), buffer + field2_offset, field2_len);
390                 memcpy(frame->get_data() + field2_len, buffer, field1_len);
391         }
392         else
393         {
394                 bcopy(buffer, frame->get_data(), buffer_size);
395         }
397         input_thread->put_buffer();
399         tuner_lock.unlock();
400         return 0;
403 int VDeviceBUZ::open_input_core(Channel *channel)
405 //printf("VDeviceBUZ::open_input_core 1\n");
406         jvideo_fd = open(device->in_config->buz_in_device, O_RDONLY);
408         if(jvideo_fd <= 0)
409         {
410                 fprintf(stderr, "VDeviceBUZ::open_input %s: %s\n", 
411                         device->in_config->buz_in_device,
412                         strerror(errno));
413                 jvideo_fd = 0;
414                 return 1;
415         }
417 // Create input sources
418         get_inputs(&device->input_sources);
420 // Set current input source
421         if(channel)
422         {
423                 for(int i = 0; i < 2; i++)
424                 {
425                         struct video_channel vch;
426                         vch.channel = channel->input;
427                         vch.norm = get_norm(channel->norm);
429 //printf("VDeviceBUZ::open_input_core 2 %d %d\n", vch.channel, vch.norm);
430                         if(ioctl(jvideo_fd, VIDIOCSCHAN, &vch) < 0)
431                                 perror("VDeviceBUZ::open_input_core VIDIOCSCHAN ");
432                 }
433         }
436 // Throw away
437     struct video_capability vc;
438         if(ioctl(jvideo_fd, VIDIOCGCAP, &vc) < 0)
439                 perror("VDeviceBUZ::open_input VIDIOCGCAP");
441 // API dependant initialization
442         if(ioctl(jvideo_fd, BUZIOC_G_PARAMS, &bparm) < 0)
443                 perror("VDeviceBUZ::open_input BUZIOC_G_PARAMS");
445         bparm.HorDcm = 1;
446         bparm.VerDcm = 1;
447         bparm.TmpDcm = 1;
448         bparm.field_per_buff = 2;
449         bparm.img_width = device->in_config->w;
450         bparm.img_height = device->in_config->h / bparm.field_per_buff;
451         bparm.img_x = 0;
452         bparm.img_y = 0;
453 //      bparm.APPn = 0;
454 //      bparm.APP_len = 14;
455         bparm.APP_len = 0;
456         bparm.odd_even = 0;
457     bparm.decimation = 0;
458     bparm.quality = device->quality;
459     bzero(bparm.APP_data, sizeof(bparm.APP_data));
461         if(ioctl(jvideo_fd, BUZIOC_S_PARAMS, &bparm) < 0)
462                 perror("VDeviceBUZ::open_input BUZIOC_S_PARAMS");
464 // printf("open_input %d %d %d %d %d %d %d %d %d %d %d %d\n", 
465 //              bparm.HorDcm,
466 //              bparm.VerDcm,
467 //              bparm.TmpDcm,
468 //              bparm.field_per_buff,
469 //              bparm.img_width,
470 //              bparm.img_height,
471 //              bparm.img_x,
472 //              bparm.img_y,
473 //              bparm.APP_len,
474 //              bparm.odd_even,
475 //      bparm.decimation,
476 //      bparm.quality);
478         breq.count = device->in_config->capture_length;
479         breq.size = INPUT_BUFFER_SIZE;
480         if(ioctl(jvideo_fd, BUZIOC_REQBUFS, &breq) < 0)
481                 perror("VDeviceBUZ::open_input BUZIOC_REQBUFS");
483 //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);
484         if((input_buffer = (char*)mmap(0, 
485                 breq.count * breq.size, 
486                 PROT_READ, 
487                 MAP_SHARED, 
488                 jvideo_fd, 
489                 0)) <= 0)
490                 perror("VDeviceBUZ::open_input mmap");
492 // Start capturing
493         for(int i = 0; i < breq.count; i++)
494         {
495         if(ioctl(jvideo_fd, BUZIOC_QBUF_CAPT, &i) < 0)
496                         perror("VDeviceBUZ::open_input BUZIOC_QBUF_CAPT");
497         }
500         input_thread = new VDeviceBUZInput(this);
501         input_thread->start();
502 //printf("VDeviceBUZ::open_input_core 2\n");
503         return 0;
506 int VDeviceBUZ::open_output_core(Channel *channel)
508 //printf("VDeviceBUZ::open_output 1\n");
509         total_loops = 0;
510         output_number = 0;
511         jvideo_fd = open(device->out_config->buz_out_device, O_RDWR);
512         if(jvideo_fd <= 0)
513         {
514                 perror("VDeviceBUZ::open_output");
515                 return 1;
516         }
519 // Set current input source
520         if(channel)
521         {
522                 struct video_channel vch;
523                 vch.channel = channel->input;
524                 vch.norm = get_norm(channel->norm);
526                 if(ioctl(jvideo_fd, VIDIOCSCHAN, &vch) < 0)
527                         perror("VDeviceBUZ::open_output_core VIDIOCSCHAN ");
528         }
530         breq.count = 10;
531         breq.size = INPUT_BUFFER_SIZE;
532         if(ioctl(jvideo_fd, BUZIOC_REQBUFS, &breq) < 0)
533                 perror("VDeviceBUZ::open_output BUZIOC_REQBUFS");
534         if((output_buffer = (char*)mmap(0, 
535                 breq.count * breq.size, 
536                 PROT_READ | PROT_WRITE, 
537                 MAP_SHARED, 
538                 jvideo_fd, 
539                 0)) <= 0)
540                 perror("VDeviceBUZ::open_output mmap");
542         if(ioctl(jvideo_fd, BUZIOC_G_PARAMS, &bparm) < 0)
543                 perror("VDeviceBUZ::open_output BUZIOC_G_PARAMS");
545         bparm.decimation = 1;
546         bparm.HorDcm = 1;
547         bparm.field_per_buff = 2;
548         bparm.TmpDcm = 1;
549         bparm.VerDcm = 1;
550         bparm.img_width = device->out_w;
551         bparm.img_height = device->out_h / bparm.field_per_buff;
552         bparm.img_x = 0;
553         bparm.img_y = 0;
554         bparm.odd_even = 0;
556         if(ioctl(jvideo_fd, BUZIOC_S_PARAMS, &bparm) < 0)
557                 perror("VDeviceBUZ::open_output BUZIOC_S_PARAMS");
558 //printf("VDeviceBUZ::open_output 2\n");
559         return 0;
564 int VDeviceBUZ::write_buffer(VFrame **frames, EDL *edl)
566 //printf("VDeviceBUZ::write_buffer 1\n");
567         tuner_lock.lock();
569         if(!jvideo_fd) open_output_core(0);
571         VFrame *ptr = 0;
572         if(frames[0]->get_color_model() != BC_COMPRESSED)
573         {
574                 if(!temp_frame) temp_frame = new VFrame;
575                 if(!mjpeg)
576                 {
577                         mjpeg = mjpeg_new(device->out_w, device->out_h, 2);
578                         mjpeg_set_quality(mjpeg, device->quality);
579                         mjpeg_set_float(mjpeg, 0);
580                 }
581                 ptr = temp_frame;
582                 mjpeg_compress(mjpeg, 
583                         frames[0]->get_rows(), 
584                         frames[0]->get_y(), 
585                         frames[0]->get_u(), 
586                         frames[0]->get_v(),
587                         frames[0]->get_color_model(),
588                         device->cpus);
589                 temp_frame->allocate_compressed_data(mjpeg_output_size(mjpeg));
590                 temp_frame->set_compressed_size(mjpeg_output_size(mjpeg));
591                 bcopy(mjpeg_output_buffer(mjpeg), temp_frame->get_data(), mjpeg_output_size(mjpeg));
592         }
593         else
594                 ptr = frames[0];
596 // Wait for frame to become available
597 // Caused close_output_core to lock up.
598 //      if(total_loops >= 1)
599 //      {
600 //              if(ioctl(jvideo_fd, BUZIOC_SYNC, &output_number) < 0)
601 //                      perror("VDeviceBUZ::write_buffer BUZIOC_SYNC");
602 //      }
604         if(device->out_config->buz_swap_fields)
605         {
606                 long field2_offset = mjpeg_get_field2((unsigned char*)ptr->get_data(), 
607                         ptr->get_compressed_size());
608                 long field2_len = ptr->get_compressed_size() - field2_offset;
609                 memcpy(output_buffer + output_number * breq.size, 
610                         ptr->get_data() + field2_offset, 
611                         field2_len);
612                 memcpy(output_buffer + output_number * breq.size +field2_len,
613                         ptr->get_data(), 
614                         field2_offset);
615         }
616         else
617         {
618                 bcopy(ptr->get_data(), 
619                         output_buffer + output_number * breq.size, 
620                         ptr->get_compressed_size());
621         }
623         if(ioctl(jvideo_fd, BUZIOC_QBUF_PLAY, &output_number) < 0)
624                 perror("VDeviceBUZ::write_buffer BUZIOC_QBUF_PLAY");
626         output_number++;
627         if(output_number >= breq.count)
628         {
629                 output_number = 0;
630                 total_loops++;
631         }
632         tuner_lock.unlock();
633 //printf("VDeviceBUZ::write_buffer 2\n");
635         return 0;
638 void VDeviceBUZ::new_output_buffer(VFrame **outputs,
639         int colormodel)
641 //printf("VDeviceBUZ::new_output_buffer 1 %d\n", colormodel);
642         if(user_frame)
643         {
644                 if(colormodel != user_frame->get_color_model())
645                 {
646                         delete user_frame;
647                         user_frame = 0;
648                 }
649         }
651         if(!user_frame)
652         {
653                 switch(colormodel)
654                 {
655                         case BC_COMPRESSED:
656                                 user_frame = new VFrame;
657                                 break;
658                         default:
659                                 user_frame = new VFrame(0,
660                                         device->out_w,
661                                         device->out_h,
662                                         colormodel,
663                                         -1);
664                                 break;
665                 }
666         }
667         user_frame->set_shm_offset(0);
668         outputs[0] = user_frame;
669 //printf("VDeviceBUZ::new_output_buffer 2\n");
673 ArrayList<int>* VDeviceBUZ::get_render_strategies()
675         return &render_strategies;