1 // ALPHA C++ can't compile 64 bit headers
2 #undef _LARGEFILE_SOURCE
3 #undef _LARGEFILE64_SOURCE
4 #undef _FILE_OFFSET_BITS
9 #include "chantables.h"
10 #include "condition.h"
13 #include "playbackconfig.h"
14 #include "preferences.h"
15 #include "recordconfig.h"
16 #include "strategies.inc"
17 #include "vdevicebuz.h"
19 #include "videoconfig.h"
20 #include "videodevice.h"
24 #include <linux/kernel.h>
25 //#include "videodev2.h"
26 #include <linux/videodev.h>
28 #include <sys/ioctl.h>
34 #define READ_TIMEOUT 5000000
37 VDeviceBUZInput::VDeviceBUZInput(VDeviceBUZ *device)
40 this->device = device;
45 current_outbuffer = 0;
47 output_lock = new Condition(0, "VDeviceBUZInput::output_lock");
48 buffer_lock = new Mutex("VDeviceBUZInput::buffer_lock");
51 VDeviceBUZInput::~VDeviceBUZInput()
62 for(int i = 0; i < total_buffers; i++)
67 delete [] buffer_size;
73 void VDeviceBUZInput::start()
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++)
82 buffer[i] = new char[INPUT_BUFFER_SIZE];
88 void VDeviceBUZInput::run()
90 struct buz_sync bsync;
95 Thread::enable_cancel();
96 if(ioctl(device->jvideo_fd, BUZIOC_SYNC, &bsync) < 0)
98 perror("VDeviceBUZInput::run BUZIOC_SYNC");
100 Thread::disable_cancel();
104 Thread::disable_cancel();
109 buffer_lock->lock("VDeviceBUZInput::run");
110 // Save only if the current buffer is free.
111 if(!buffer_size[current_inbuffer])
114 // Copy to input buffer
115 memcpy(buffer[current_inbuffer],
116 device->input_buffer + bsync.frame * device->breq.size,
119 // Advance input buffer number and decrease semaphore.
120 buffer_size[current_inbuffer] = bsync.length;
121 increment_counter(¤t_inbuffer);
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();
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.
143 // output_lock->lock("VDeviceBUZInput::get_buffer");
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();
155 //printf("VDeviceBUZInput::get_buffer 1\n");
156 output_lock->unlock();
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(¤t_outbuffer);
168 void VDeviceBUZInput::increment_counter(int *counter)
171 if(*counter >= total_buffers) *counter = 0;
174 void VDeviceBUZInput::decrement_counter(int *counter)
177 if(*counter < 0) *counter = total_buffers - 1;
194 VDeviceBUZ::VDeviceBUZ(VideoDevice *device)
195 : VDeviceBase(device)
198 render_strategies.append(VRENDER_MJPG);
199 tuner_lock = new Mutex("VDeviceBUZ::tuner_lock");
202 VDeviceBUZ::~VDeviceBUZ()
208 int VDeviceBUZ::reset_parameters()
231 int VDeviceBUZ::close_input_core()
242 if(jvideo_fd) close(jvideo_fd);
249 munmap(input_buffer, breq.count * breq.size);
254 int VDeviceBUZ::close_output_core()
256 //printf("VDeviceBUZ::close_output_core 1\n");
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);
267 if(output_buffer > 0)
268 munmap(output_buffer, breq.count * breq.size);
286 //printf("VDeviceBUZ::close_output_core 2\n");
291 int VDeviceBUZ::close_all()
293 //printf("VDeviceBUZ::close_all 1\n");
295 //printf("VDeviceBUZ::close_all 1\n");
297 //printf("VDeviceBUZ::close_all 1\n");
298 if(frame_buffer) delete frame_buffer;
299 //printf("VDeviceBUZ::close_all 1\n");
301 //printf("VDeviceBUZ::close_all 2\n");
305 #define COMPOSITE_TEXT "Composite"
306 #define SVIDEO_TEXT "S-Video"
307 #define BUZ_COMPOSITE 0
310 void VDeviceBUZ::get_inputs(ArrayList<char *> *input_sources)
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
325 int VDeviceBUZ::open_output()
327 // Can't open output until after the channel is set
331 int VDeviceBUZ::set_channel(Channel *channel)
333 if(!channel) return 0;
335 tuner_lock->lock("VDeviceBUZ::set_channel");
340 open_input_core(channel);
345 open_output_core(channel);
348 tuner_lock->unlock();
354 void VDeviceBUZ::create_channeldb(ArrayList<Channel*> *channeldb)
359 int VDeviceBUZ::set_picture(int brightness,
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");
383 tuner_lock->unlock();
386 // TRACE("VDeviceBUZ::set_picture 1");
387 // tuner_lock->lock("VDeviceBUZ::set_picture");
388 // TRACE("VDeviceBUZ::set_picture 2");
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");
408 // TRACE("VDeviceBUZ::set_picture 10");
411 // tuner_lock->unlock();
416 int VDeviceBUZ::get_norm(int norm)
420 case NTSC: return VIDEO_MODE_NTSC; break;
421 case PAL: return VIDEO_MODE_PAL; break;
422 case SECAM: return VIDEO_MODE_SECAM; break;
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
436 input_thread->get_buffer(&buffer, &buffer_size);
437 //printf("%lld ", timer.get_difference());fflush(stdout);
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)
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);
456 bcopy(buffer, frame->get_data(), buffer_size);
459 input_thread->put_buffer();
460 tuner_lock->unlock();
464 tuner_lock->unlock();
466 //printf("VDeviceBUZ::read_buffer 1\n");
467 // Allow other threads to lock the tuner_lock under NPTL.
475 int VDeviceBUZ::open_input_core(Channel *channel)
477 jvideo_fd = open(device->in_config->buz_in_device, O_RDONLY);
481 fprintf(stderr, "VDeviceBUZ::open_input %s: %s\n",
482 device->in_config->buz_in_device,
488 // Create input sources
489 get_inputs(&device->input_sources);
491 // Set current input source
494 for(int i = 0; i < 2; i++)
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 ");
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");
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;
525 // bparm.APP_len = 14;
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",
539 // bparm.field_per_buff,
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,
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");
584 for(int i = 0; i < breq.count; i++)
586 if(ioctl(jvideo_fd, BUZIOC_QBUF_CAPT, &i) < 0)
587 perror("VDeviceBUZ::open_input BUZIOC_QBUF_CAPT");
591 input_thread = new VDeviceBUZInput(this);
592 input_thread->start();
593 //printf("VDeviceBUZ::open_input_core 2\n");
597 int VDeviceBUZ::open_output_core(Channel *channel)
599 //printf("VDeviceBUZ::open_output 1\n");
602 jvideo_fd = open(device->out_config->buz_out_device, O_RDWR);
605 perror("VDeviceBUZ::open_output");
610 // Set current input source
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 ");
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,
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;
638 bparm.field_per_buff = 2;
641 bparm.img_width = device->out_w;
642 bparm.img_height = device->out_h / bparm.field_per_buff;
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");
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);
663 if(frames[0]->get_color_model() != BC_COMPRESSED)
665 if(!temp_frame) temp_frame = new VFrame;
668 mjpeg = mjpeg_new(device->out_w, device->out_h, 2);
669 mjpeg_set_quality(mjpeg, device->quality);
670 mjpeg_set_float(mjpeg, 0);
673 mjpeg_compress(mjpeg,
674 frames[0]->get_rows(),
678 frames[0]->get_color_model(),
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));
687 // Wait for frame to become available
688 // Caused close_output_core to lock up.
689 // if(total_loops >= 1)
691 // if(ioctl(jvideo_fd, BUZIOC_SYNC, &output_number) < 0)
692 // perror("VDeviceBUZ::write_buffer BUZIOC_SYNC");
695 if(device->out_config->buz_swap_fields)
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,
703 memcpy(output_buffer + output_number * breq.size +field2_len,
709 bcopy(ptr->get_data(),
710 output_buffer + output_number * breq.size,
711 ptr->get_compressed_size());
714 if(ioctl(jvideo_fd, BUZIOC_QBUF_PLAY, &output_number) < 0)
715 perror("VDeviceBUZ::write_buffer BUZIOC_QBUF_PLAY");
718 if(output_number >= breq.count)
723 tuner_lock->unlock();
724 //printf("VDeviceBUZ::write_buffer 2\n");
729 void VDeviceBUZ::new_output_buffer(VFrame **outputs,
732 //printf("VDeviceBUZ::new_output_buffer 1 %d\n", colormodel);
735 if(colormodel != user_frame->get_color_model())
747 user_frame = new VFrame;
750 user_frame = new VFrame(0,
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;