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"
14 #include "playbackconfig.h"
15 #include "preferences.h"
16 #include "recordconfig.h"
17 #include "strategies.inc"
18 #include "vdevicebuz.h"
20 #include "videoconfig.h"
21 #include "videodevice.h"
25 #include <linux/kernel.h>
26 //#include <linux/videodev2.h>
27 #include <linux/videodev.h>
29 #include <sys/ioctl.h>
35 #define READ_TIMEOUT 5000000
38 VDeviceBUZInput::VDeviceBUZInput(VDeviceBUZ *device)
41 this->device = device;
46 current_outbuffer = 0;
48 output_lock = new Condition(0, "VDeviceBUZInput::output_lock");
49 buffer_lock = new Mutex("VDeviceBUZInput::buffer_lock");
52 VDeviceBUZInput::~VDeviceBUZInput()
63 for(int i = 0; i < total_buffers; i++)
68 delete [] buffer_size;
74 void VDeviceBUZInput::start()
77 total_buffers = device->device->in_config->capture_length;
78 buffer = new char*[total_buffers];
79 buffer_size = new int[total_buffers];
80 bzero(buffer_size, sizeof(int) * total_buffers);
81 for(int i = 0; i < total_buffers; i++)
83 buffer[i] = new char[INPUT_BUFFER_SIZE];
89 void VDeviceBUZInput::run()
91 struct buz_sync bsync;
96 Thread::enable_cancel();
97 if(ioctl(device->jvideo_fd, BUZIOC_SYNC, &bsync) < 0)
99 perror("VDeviceBUZInput::run BUZIOC_SYNC");
101 Thread::disable_cancel();
105 Thread::disable_cancel();
110 buffer_lock->lock("VDeviceBUZInput::run");
111 // Save only if the current buffer is free.
112 if(!buffer_size[current_inbuffer])
115 // Copy to input buffer
116 memcpy(buffer[current_inbuffer],
117 device->input_buffer + bsync.frame * device->breq.size,
120 // Advance input buffer number and decrease semaphore.
121 buffer_size[current_inbuffer] = bsync.length;
122 increment_counter(¤t_inbuffer);
125 buffer_lock->unlock();
127 if(ioctl(device->jvideo_fd, BUZIOC_QBUF_CAPT, &bsync.frame))
128 perror("VDeviceBUZInput::run BUZIOC_QBUF_CAPT");
130 if(new_buffer) output_lock->unlock();
135 void VDeviceBUZInput::get_buffer(char **ptr, int *size)
137 // Increase semaphore to wait for buffer.
138 int result = output_lock->timed_lock(READ_TIMEOUT, "VDeviceBUZInput::get_buffer");
141 // The driver has its own timeout routine but it doesn't work because
142 // because the tuner lock is unlocked and relocked with no delay.
144 // output_lock->lock("VDeviceBUZInput::get_buffer");
148 // Take over buffer table
149 buffer_lock->lock("VDeviceBUZInput::get_buffer");
150 *ptr = buffer[current_outbuffer];
151 *size = buffer_size[current_outbuffer];
152 buffer_lock->unlock();
156 //printf("VDeviceBUZInput::get_buffer 1\n");
157 output_lock->unlock();
161 void VDeviceBUZInput::put_buffer()
163 buffer_lock->lock("VDeviceBUZInput::put_buffer");
164 buffer_size[current_outbuffer] = 0;
165 buffer_lock->unlock();
166 increment_counter(¤t_outbuffer);
169 void VDeviceBUZInput::increment_counter(int *counter)
172 if(*counter >= total_buffers) *counter = 0;
175 void VDeviceBUZInput::decrement_counter(int *counter)
178 if(*counter < 0) *counter = total_buffers - 1;
195 VDeviceBUZ::VDeviceBUZ(VideoDevice *device)
196 : VDeviceBase(device)
199 render_strategies.append(VRENDER_MJPG);
200 tuner_lock = new Mutex("VDeviceBUZ::tuner_lock");
203 VDeviceBUZ::~VDeviceBUZ()
209 int VDeviceBUZ::reset_parameters()
232 int VDeviceBUZ::close_input_core()
243 if(jvideo_fd) close(jvideo_fd);
250 munmap(input_buffer, breq.count * breq.size);
255 int VDeviceBUZ::close_output_core()
257 //printf("VDeviceBUZ::close_output_core 1\n");
261 // if(ioctl(jvideo_fd, BUZIOC_QBUF_PLAY, &n) < 0)
262 // perror("VDeviceBUZ::close_output_core BUZIOC_QBUF_PLAY");
263 if(jvideo_fd) close(jvideo_fd);
268 if(output_buffer > 0)
269 munmap(output_buffer, breq.count * breq.size);
287 //printf("VDeviceBUZ::close_output_core 2\n");
292 int VDeviceBUZ::close_all()
294 //printf("VDeviceBUZ::close_all 1\n");
296 //printf("VDeviceBUZ::close_all 1\n");
298 //printf("VDeviceBUZ::close_all 1\n");
299 if(frame_buffer) delete frame_buffer;
300 //printf("VDeviceBUZ::close_all 1\n");
302 //printf("VDeviceBUZ::close_all 2\n");
306 #define COMPOSITE_TEXT "Composite"
307 #define SVIDEO_TEXT "S-Video"
308 #define BUZ_COMPOSITE 0
311 void VDeviceBUZ::get_inputs(ArrayList<Channel*> *input_sources)
313 Channel *new_source = new Channel;
315 new_source = new Channel;
316 strcpy(new_source->device_name, COMPOSITE_TEXT);
317 input_sources->append(new_source);
319 new_source = new Channel;
320 strcpy(new_source->device_name, SVIDEO_TEXT);
321 input_sources->append(new_source);
324 int VDeviceBUZ::open_input()
326 device->channel->use_norm = 1;
327 device->channel->use_input = 1;
329 device->picture->use_brightness = 1;
330 device->picture->use_contrast = 1;
331 device->picture->use_color = 1;
332 device->picture->use_hue = 1;
333 device->picture->use_whiteness = 1;
335 // Can't open input until after the channel is set
339 int VDeviceBUZ::open_output()
341 // Can't open output until after the channel is set
345 int VDeviceBUZ::set_channel(Channel *channel)
347 if(!channel) return 0;
349 tuner_lock->lock("VDeviceBUZ::set_channel");
354 open_input_core(channel);
359 open_output_core(channel);
362 tuner_lock->unlock();
368 void VDeviceBUZ::create_channeldb(ArrayList<Channel*> *channeldb)
373 int VDeviceBUZ::set_picture(Picture *picture)
375 this->brightness = (int)((float)picture->brightness / 100 * 32767 + 32768);
376 this->hue = (int)((float)picture->hue / 100 * 32767 + 32768);
377 this->color = (int)((float)picture->color / 100 * 32767 + 32768);
378 this->contrast = (int)((float)picture->contrast / 100 * 32767 + 32768);
379 this->whiteness = (int)((float)picture->whiteness / 100 * 32767 + 32768);
382 tuner_lock->lock("VDeviceBUZ::set_picture");
393 tuner_lock->unlock();
396 // TRACE("VDeviceBUZ::set_picture 1");
397 // tuner_lock->lock("VDeviceBUZ::set_picture");
398 // TRACE("VDeviceBUZ::set_picture 2");
402 // struct video_picture picture_params;
403 // // This call takes a long time in 2.4.22
404 // if(ioctl(jvideo_fd, VIDIOCGPICT, &picture_params) < 0)
405 // perror("VDeviceBUZ::set_picture VIDIOCGPICT");
406 // picture_params.brightness = brightness;
407 // picture_params.hue = hue;
408 // picture_params.colour = color;
409 // picture_params.contrast = contrast;
410 // picture_params.whiteness = whiteness;
411 // // This call takes a long time in 2.4.22
412 // if(ioctl(jvideo_fd, VIDIOCSPICT, &picture_params) < 0)
413 // perror("VDeviceBUZ::set_picture VIDIOCSPICT");
414 // if(ioctl(jvideo_fd, VIDIOCGPICT, &picture_params) < 0)
415 // perror("VDeviceBUZ::set_picture VIDIOCGPICT");
418 // TRACE("VDeviceBUZ::set_picture 10");
421 // tuner_lock->unlock();
426 int VDeviceBUZ::get_norm(int norm)
430 case NTSC: return VIDEO_MODE_NTSC; break;
431 case PAL: return VIDEO_MODE_PAL; break;
432 case SECAM: return VIDEO_MODE_SECAM; break;
436 int VDeviceBUZ::read_buffer(VFrame *frame)
438 tuner_lock->lock("VDeviceBUZ::read_buffer");
439 if(!jvideo_fd) open_input_core(0);
441 // Get buffer from thread
445 input_thread->get_buffer(&buffer, &buffer_size);
449 frame->allocate_compressed_data(buffer_size);
450 frame->set_compressed_size(buffer_size);
452 // Transfer fields to frame
453 if(device->odd_field_first)
455 long field2_offset = mjpeg_get_field2((unsigned char*)buffer, buffer_size);
456 long field1_len = field2_offset;
457 long field2_len = buffer_size - field2_offset;
459 memcpy(frame->get_data(), buffer + field2_offset, field2_len);
460 memcpy(frame->get_data() + field2_len, buffer, field1_len);
464 bcopy(buffer, frame->get_data(), buffer_size);
467 input_thread->put_buffer();
468 tuner_lock->unlock();
472 tuner_lock->unlock();
474 // Allow other threads to lock the tuner_lock under NPTL.
482 int VDeviceBUZ::open_input_core(Channel *channel)
484 jvideo_fd = open(device->in_config->buz_in_device, O_RDONLY);
488 fprintf(stderr, "VDeviceBUZ::open_input %s: %s\n",
489 device->in_config->buz_in_device,
495 // Create input sources
496 get_inputs(&device->input_sources);
498 // Set current input source
501 for(int i = 0; i < 2; i++)
503 struct video_channel vch;
504 vch.channel = channel->input;
505 vch.norm = get_norm(channel->norm);
507 //printf("VDeviceBUZ::open_input_core 2 %d %d\n", vch.channel, vch.norm);
508 if(ioctl(jvideo_fd, VIDIOCSCHAN, &vch) < 0)
509 perror("VDeviceBUZ::open_input_core VIDIOCSCHAN ");
515 // struct video_capability vc;
516 // if(ioctl(jvideo_fd, VIDIOCGCAP, &vc) < 0)
517 // perror("VDeviceBUZ::open_input VIDIOCGCAP");
519 // API dependant initialization
520 if(ioctl(jvideo_fd, BUZIOC_G_PARAMS, &bparm) < 0)
521 perror("VDeviceBUZ::open_input BUZIOC_G_PARAMS");
526 bparm.field_per_buff = 2;
527 bparm.img_width = device->in_config->w;
528 bparm.img_height = device->in_config->h / bparm.field_per_buff;
532 // bparm.APP_len = 14;
535 bparm.decimation = 0;
536 bparm.quality = device->quality;
537 bzero(bparm.APP_data, sizeof(bparm.APP_data));
539 if(ioctl(jvideo_fd, BUZIOC_S_PARAMS, &bparm) < 0)
540 perror("VDeviceBUZ::open_input BUZIOC_S_PARAMS");
542 // printf("open_input %d %d %d %d %d %d %d %d %d %d %d %d\n",
546 // bparm.field_per_buff,
556 breq.count = device->in_config->capture_length;
557 breq.size = INPUT_BUFFER_SIZE;
558 if(ioctl(jvideo_fd, BUZIOC_REQBUFS, &breq) < 0)
559 perror("VDeviceBUZ::open_input BUZIOC_REQBUFS");
561 //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);
562 if((input_buffer = (char*)mmap(0,
563 breq.count * breq.size,
568 perror("VDeviceBUZ::open_input mmap");
571 // Set picture quality
572 struct video_picture picture_params;
573 // This call takes a long time in 2.4.22
574 if(ioctl(jvideo_fd, VIDIOCGPICT, &picture_params) < 0)
575 perror("VDeviceBUZ::set_picture VIDIOCGPICT");
576 picture_params.brightness = brightness;
577 picture_params.hue = hue;
578 picture_params.colour = color;
579 picture_params.contrast = contrast;
580 picture_params.whiteness = whiteness;
581 // This call takes a long time in 2.4.22
582 if(ioctl(jvideo_fd, VIDIOCSPICT, &picture_params) < 0)
583 perror("VDeviceBUZ::set_picture VIDIOCSPICT");
584 if(ioctl(jvideo_fd, VIDIOCGPICT, &picture_params) < 0)
585 perror("VDeviceBUZ::set_picture VIDIOCGPICT");
591 for(int i = 0; i < breq.count; i++)
593 if(ioctl(jvideo_fd, BUZIOC_QBUF_CAPT, &i) < 0)
594 perror("VDeviceBUZ::open_input BUZIOC_QBUF_CAPT");
598 input_thread = new VDeviceBUZInput(this);
599 input_thread->start();
600 //printf("VDeviceBUZ::open_input_core 2\n");
604 int VDeviceBUZ::open_output_core(Channel *channel)
606 //printf("VDeviceBUZ::open_output 1\n");
609 jvideo_fd = open(device->out_config->buz_out_device, O_RDWR);
612 perror("VDeviceBUZ::open_output");
617 // Set current input source
620 struct video_channel vch;
621 vch.channel = channel->input;
622 vch.norm = get_norm(channel->norm);
624 if(ioctl(jvideo_fd, VIDIOCSCHAN, &vch) < 0)
625 perror("VDeviceBUZ::open_output_core VIDIOCSCHAN ");
629 breq.size = INPUT_BUFFER_SIZE;
630 if(ioctl(jvideo_fd, BUZIOC_REQBUFS, &breq) < 0)
631 perror("VDeviceBUZ::open_output BUZIOC_REQBUFS");
632 if((output_buffer = (char*)mmap(0,
633 breq.count * breq.size,
634 PROT_READ | PROT_WRITE,
638 perror("VDeviceBUZ::open_output mmap");
640 if(ioctl(jvideo_fd, BUZIOC_G_PARAMS, &bparm) < 0)
641 perror("VDeviceBUZ::open_output BUZIOC_G_PARAMS");
643 bparm.decimation = 1;
645 bparm.field_per_buff = 2;
648 bparm.img_width = device->out_w;
649 bparm.img_height = device->out_h / bparm.field_per_buff;
654 if(ioctl(jvideo_fd, BUZIOC_S_PARAMS, &bparm) < 0)
655 perror("VDeviceBUZ::open_output BUZIOC_S_PARAMS");
656 //printf("VDeviceBUZ::open_output 2\n");
662 int VDeviceBUZ::write_buffer(VFrame **frames, EDL *edl)
664 //printf("VDeviceBUZ::write_buffer 1\n");
665 tuner_lock->lock("VDeviceBUZ::write_buffer");
667 if(!jvideo_fd) open_output_core(0);
670 if(frames[0]->get_color_model() != BC_COMPRESSED)
672 if(!temp_frame) temp_frame = new VFrame;
675 mjpeg = mjpeg_new(device->out_w, device->out_h, 2);
676 mjpeg_set_quality(mjpeg, device->quality);
677 mjpeg_set_float(mjpeg, 0);
680 mjpeg_compress(mjpeg,
681 frames[0]->get_rows(),
685 frames[0]->get_color_model(),
687 temp_frame->allocate_compressed_data(mjpeg_output_size(mjpeg));
688 temp_frame->set_compressed_size(mjpeg_output_size(mjpeg));
689 bcopy(mjpeg_output_buffer(mjpeg), temp_frame->get_data(), mjpeg_output_size(mjpeg));
694 // Wait for frame to become available
695 // Caused close_output_core to lock up.
696 // if(total_loops >= 1)
698 // if(ioctl(jvideo_fd, BUZIOC_SYNC, &output_number) < 0)
699 // perror("VDeviceBUZ::write_buffer BUZIOC_SYNC");
702 if(device->out_config->buz_swap_fields)
704 long field2_offset = mjpeg_get_field2((unsigned char*)ptr->get_data(),
705 ptr->get_compressed_size());
706 long field2_len = ptr->get_compressed_size() - field2_offset;
707 memcpy(output_buffer + output_number * breq.size,
708 ptr->get_data() + field2_offset,
710 memcpy(output_buffer + output_number * breq.size +field2_len,
716 bcopy(ptr->get_data(),
717 output_buffer + output_number * breq.size,
718 ptr->get_compressed_size());
721 if(ioctl(jvideo_fd, BUZIOC_QBUF_PLAY, &output_number) < 0)
722 perror("VDeviceBUZ::write_buffer BUZIOC_QBUF_PLAY");
725 if(output_number >= breq.count)
730 tuner_lock->unlock();
731 //printf("VDeviceBUZ::write_buffer 2\n");
736 void VDeviceBUZ::new_output_buffer(VFrame **outputs,
739 //printf("VDeviceBUZ::new_output_buffer 1 %d\n", colormodel);
742 if(colormodel != user_frame->get_color_model())
754 user_frame = new VFrame;
757 user_frame = new VFrame(0,
765 user_frame->set_shm_offset(0);
766 outputs[0] = user_frame;
767 //printf("VDeviceBUZ::new_output_buffer 2\n");
771 ArrayList<int>* VDeviceBUZ::get_render_strategies()
773 return &render_strategies;