00001
00002 #undef _LARGEFILE_SOURCE
00003 #undef _LARGEFILE64_SOURCE
00004 #undef _FILE_OFFSET_BITS
00005
00006 #include "assets.h"
00007 #include "bcsignals.h"
00008 #include "channel.h"
00009 #include "chantables.h"
00010 #include "condition.h"
00011 #include "file.inc"
00012 #include "mutex.h"
00013 #include "picture.h"
00014 #include "playbackconfig.h"
00015 #include "preferences.h"
00016 #include "recordconfig.h"
00017 #include "strategies.inc"
00018 #include "vdevicebuz.h"
00019 #include "vframe.h"
00020 #include "videoconfig.h"
00021 #include "videodevice.h"
00022
00023 #include <errno.h>
00024 #include <stdint.h>
00025 #include <linux/kernel.h>
00026
00027 #include <linux/videodev.h>
00028 #include <fcntl.h>
00029 #include <sys/ioctl.h>
00030 #include <sys/mman.h>
00031 #include <unistd.h>
00032
00033
00034
00035 #define READ_TIMEOUT 5000000
00036
00037
00038 VDeviceBUZInput::VDeviceBUZInput(VDeviceBUZ *device)
00039 : Thread(1, 1, 0)
00040 {
00041 this->device = device;
00042 buffer = 0;
00043 buffer_size = 0;
00044 total_buffers = 0;
00045 current_inbuffer = 0;
00046 current_outbuffer = 0;
00047 done = 0;
00048 output_lock = new Condition(0, "VDeviceBUZInput::output_lock");
00049 buffer_lock = new Mutex("VDeviceBUZInput::buffer_lock");
00050 }
00051
00052 VDeviceBUZInput::~VDeviceBUZInput()
00053 {
00054 if(Thread::running())
00055 {
00056 done = 1;
00057 Thread::cancel();
00058 Thread::join();
00059 }
00060
00061 if(buffer)
00062 {
00063 for(int i = 0; i < total_buffers; i++)
00064 {
00065 delete [] buffer[i];
00066 }
00067 delete [] buffer;
00068 delete [] buffer_size;
00069 }
00070 delete output_lock;
00071 delete buffer_lock;
00072 }
00073
00074 void VDeviceBUZInput::start()
00075 {
00076
00077 total_buffers = device->device->in_config->capture_length;
00078 buffer = new char*[total_buffers];
00079 buffer_size = new int[total_buffers];
00080 bzero(buffer_size, sizeof(int) * total_buffers);
00081 for(int i = 0; i < total_buffers; i++)
00082 {
00083 buffer[i] = new char[INPUT_BUFFER_SIZE];
00084 }
00085
00086 Thread::start();
00087 }
00088
00089 void VDeviceBUZInput::run()
00090 {
00091 struct buz_sync bsync;
00092
00093
00094 while(1)
00095 {
00096 Thread::enable_cancel();
00097 if(ioctl(device->jvideo_fd, BUZIOC_SYNC, &bsync) < 0)
00098 {
00099 perror("VDeviceBUZInput::run BUZIOC_SYNC");
00100 if(done) return;
00101 Thread::disable_cancel();
00102 }
00103 else
00104 {
00105 Thread::disable_cancel();
00106
00107
00108
00109 int new_buffer = 0;
00110 buffer_lock->lock("VDeviceBUZInput::run");
00111
00112 if(!buffer_size[current_inbuffer])
00113 {
00114 new_buffer = 1;
00115
00116 memcpy(buffer[current_inbuffer],
00117 device->input_buffer + bsync.frame * device->breq.size,
00118 bsync.length);
00119
00120
00121 buffer_size[current_inbuffer] = bsync.length;
00122 increment_counter(¤t_inbuffer);
00123 }
00124
00125 buffer_lock->unlock();
00126
00127 if(ioctl(device->jvideo_fd, BUZIOC_QBUF_CAPT, &bsync.frame))
00128 perror("VDeviceBUZInput::run BUZIOC_QBUF_CAPT");
00129
00130 if(new_buffer) output_lock->unlock();
00131 }
00132 }
00133 }
00134
00135 void VDeviceBUZInput::get_buffer(char **ptr, int *size)
00136 {
00137
00138 int result = output_lock->timed_lock(READ_TIMEOUT, "VDeviceBUZInput::get_buffer");
00139
00140
00141
00142
00143
00144
00145
00146 if(!result)
00147 {
00148
00149 buffer_lock->lock("VDeviceBUZInput::get_buffer");
00150 *ptr = buffer[current_outbuffer];
00151 *size = buffer_size[current_outbuffer];
00152 buffer_lock->unlock();
00153 }
00154 else
00155 {
00156
00157 output_lock->unlock();
00158 }
00159 }
00160
00161 void VDeviceBUZInput::put_buffer()
00162 {
00163 buffer_lock->lock("VDeviceBUZInput::put_buffer");
00164 buffer_size[current_outbuffer] = 0;
00165 buffer_lock->unlock();
00166 increment_counter(¤t_outbuffer);
00167 }
00168
00169 void VDeviceBUZInput::increment_counter(int *counter)
00170 {
00171 (*counter)++;
00172 if(*counter >= total_buffers) *counter = 0;
00173 }
00174
00175 void VDeviceBUZInput::decrement_counter(int *counter)
00176 {
00177 (*counter)--;
00178 if(*counter < 0) *counter = total_buffers - 1;
00179 }
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195 VDeviceBUZ::VDeviceBUZ(VideoDevice *device)
00196 : VDeviceBase(device)
00197 {
00198 reset_parameters();
00199 render_strategies.append(VRENDER_MJPG);
00200 tuner_lock = new Mutex("VDeviceBUZ::tuner_lock");
00201 }
00202
00203 VDeviceBUZ::~VDeviceBUZ()
00204 {
00205 close_all();
00206 delete tuner_lock;
00207 }
00208
00209 int VDeviceBUZ::reset_parameters()
00210 {
00211 jvideo_fd = 0;
00212 input_buffer = 0;
00213 output_buffer = 0;
00214 frame_buffer = 0;
00215 frame_size = 0;
00216 frame_allocated = 0;
00217 input_error = 0;
00218 last_frame_no = 0;
00219 temp_frame = 0;
00220 user_frame = 0;
00221 mjpeg = 0;
00222 total_loops = 0;
00223 output_number = 0;
00224 input_thread = 0;
00225 brightness = 32768;
00226 hue = 32768;
00227 color = 32768;
00228 contrast = 32768;
00229 whiteness = 32768;
00230 }
00231
00232 int VDeviceBUZ::close_input_core()
00233 {
00234 if(input_thread)
00235 {
00236 delete input_thread;
00237 input_thread = 0;
00238 }
00239
00240
00241 if(device->r)
00242 {
00243 if(jvideo_fd) close(jvideo_fd);
00244 jvideo_fd = 0;
00245 }
00246
00247 if(input_buffer)
00248 {
00249 if(input_buffer > 0)
00250 munmap(input_buffer, breq.count * breq.size);
00251 input_buffer = 0;
00252 }
00253 }
00254
00255 int VDeviceBUZ::close_output_core()
00256 {
00257
00258 if(device->w)
00259 {
00260 int n = -1;
00261
00262
00263 if(jvideo_fd) close(jvideo_fd);
00264 jvideo_fd = 0;
00265 }
00266 if(output_buffer)
00267 {
00268 if(output_buffer > 0)
00269 munmap(output_buffer, breq.count * breq.size);
00270 output_buffer = 0;
00271 }
00272 if(temp_frame)
00273 {
00274 delete temp_frame;
00275 temp_frame = 0;
00276 }
00277 if(mjpeg)
00278 {
00279 mjpeg_delete(mjpeg);
00280 mjpeg = 0;
00281 }
00282 if(user_frame)
00283 {
00284 delete user_frame;
00285 user_frame = 0;
00286 }
00287
00288 return 0;
00289 }
00290
00291
00292 int VDeviceBUZ::close_all()
00293 {
00294
00295 close_input_core();
00296
00297 close_output_core();
00298
00299 if(frame_buffer) delete frame_buffer;
00300
00301 reset_parameters();
00302
00303 return 0;
00304 }
00305
00306 #define COMPOSITE_TEXT "Composite"
00307 #define SVIDEO_TEXT "S-Video"
00308 #define BUZ_COMPOSITE 0
00309 #define BUZ_SVIDEO 1
00310
00311 void VDeviceBUZ::get_inputs(ArrayList<Channel*> *input_sources)
00312 {
00313 Channel *new_source = new Channel;
00314
00315 new_source = new Channel;
00316 strcpy(new_source->device_name, COMPOSITE_TEXT);
00317 input_sources->append(new_source);
00318
00319 new_source = new Channel;
00320 strcpy(new_source->device_name, SVIDEO_TEXT);
00321 input_sources->append(new_source);
00322 }
00323
00324 int VDeviceBUZ::open_input()
00325 {
00326 device->channel->use_norm = 1;
00327 device->channel->use_input = 1;
00328
00329 device->picture->use_brightness = 1;
00330 device->picture->use_contrast = 1;
00331 device->picture->use_color = 1;
00332 device->picture->use_hue = 1;
00333 device->picture->use_whiteness = 1;
00334
00335
00336 return 0;
00337 }
00338
00339 int VDeviceBUZ::open_output()
00340 {
00341
00342 return 0;
00343 }
00344
00345 int VDeviceBUZ::set_channel(Channel *channel)
00346 {
00347 if(!channel) return 0;
00348
00349 tuner_lock->lock("VDeviceBUZ::set_channel");
00350
00351 if(device->r)
00352 {
00353 close_input_core();
00354 open_input_core(channel);
00355 }
00356 else
00357 {
00358 close_output_core();
00359 open_output_core(channel);
00360 }
00361
00362 tuner_lock->unlock();
00363
00364
00365 return 0;
00366 }
00367
00368 void VDeviceBUZ::create_channeldb(ArrayList<Channel*> *channeldb)
00369 {
00370 ;
00371 }
00372
00373 int VDeviceBUZ::set_picture(PictureConfig *picture)
00374 {
00375 this->brightness = (int)((float)picture->brightness / 100 * 32767 + 32768);
00376 this->hue = (int)((float)picture->hue / 100 * 32767 + 32768);
00377 this->color = (int)((float)picture->color / 100 * 32767 + 32768);
00378 this->contrast = (int)((float)picture->contrast / 100 * 32767 + 32768);
00379 this->whiteness = (int)((float)picture->whiteness / 100 * 32767 + 32768);
00380
00381
00382 tuner_lock->lock("VDeviceBUZ::set_picture");
00383 if(device->r)
00384 {
00385 close_input_core();
00386 open_input_core(0);
00387 }
00388 else
00389 {
00390 close_output_core();
00391 open_output_core(0);
00392 }
00393 tuner_lock->unlock();
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423 return 0;
00424 }
00425
00426 int VDeviceBUZ::get_norm(int norm)
00427 {
00428 switch(norm)
00429 {
00430 case NTSC: return VIDEO_MODE_NTSC; break;
00431 case PAL: return VIDEO_MODE_PAL; break;
00432 case SECAM: return VIDEO_MODE_SECAM; break;
00433 }
00434 }
00435
00436 int VDeviceBUZ::read_buffer(VFrame *frame)
00437 {
00438 tuner_lock->lock("VDeviceBUZ::read_buffer");
00439 if(!jvideo_fd) open_input_core(0);
00440
00441
00442 char *buffer = 0;
00443 int buffer_size = 0;
00444 if(input_thread)
00445 input_thread->get_buffer(&buffer, &buffer_size);
00446
00447 if(buffer)
00448 {
00449 frame->allocate_compressed_data(buffer_size);
00450 frame->set_compressed_size(buffer_size);
00451
00452
00453 if(device->odd_field_first)
00454 {
00455 long field2_offset = mjpeg_get_field2((unsigned char*)buffer, buffer_size);
00456 long field1_len = field2_offset;
00457 long field2_len = buffer_size - field2_offset;
00458
00459 memcpy(frame->get_data(), buffer + field2_offset, field2_len);
00460 memcpy(frame->get_data() + field2_len, buffer, field1_len);
00461 }
00462 else
00463 {
00464 bcopy(buffer, frame->get_data(), buffer_size);
00465 }
00466
00467 input_thread->put_buffer();
00468 tuner_lock->unlock();
00469 }
00470 else
00471 {
00472 tuner_lock->unlock();
00473 Timer timer;
00474
00475 timer.delay(100);
00476 }
00477
00478
00479 return 0;
00480 }
00481
00482 int VDeviceBUZ::open_input_core(Channel *channel)
00483 {
00484 jvideo_fd = open(device->in_config->buz_in_device, O_RDONLY);
00485
00486 if(jvideo_fd <= 0)
00487 {
00488 fprintf(stderr, "VDeviceBUZ::open_input %s: %s\n",
00489 device->in_config->buz_in_device,
00490 strerror(errno));
00491 jvideo_fd = 0;
00492 return 1;
00493 }
00494
00495
00496 get_inputs(&device->input_sources);
00497
00498
00499 if(channel)
00500 {
00501 for(int i = 0; i < 2; i++)
00502 {
00503 struct video_channel vch;
00504 vch.channel = channel->input;
00505 vch.norm = get_norm(channel->norm);
00506
00507
00508 if(ioctl(jvideo_fd, VIDIOCSCHAN, &vch) < 0)
00509 perror("VDeviceBUZ::open_input_core VIDIOCSCHAN ");
00510 }
00511 }
00512
00513
00514
00515
00516
00517
00518
00519
00520 if(ioctl(jvideo_fd, BUZIOC_G_PARAMS, &bparm) < 0)
00521 perror("VDeviceBUZ::open_input BUZIOC_G_PARAMS");
00522
00523 bparm.HorDcm = 1;
00524 bparm.VerDcm = 1;
00525 bparm.TmpDcm = 1;
00526 bparm.field_per_buff = 2;
00527 bparm.img_width = device->in_config->w;
00528 bparm.img_height = device->in_config->h / bparm.field_per_buff;
00529 bparm.img_x = 0;
00530 bparm.img_y = 0;
00531
00532
00533 bparm.APP_len = 0;
00534 bparm.odd_even = 0;
00535 bparm.decimation = 0;
00536 bparm.quality = device->quality;
00537 bzero(bparm.APP_data, sizeof(bparm.APP_data));
00538
00539 if(ioctl(jvideo_fd, BUZIOC_S_PARAMS, &bparm) < 0)
00540 perror("VDeviceBUZ::open_input BUZIOC_S_PARAMS");
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556 breq.count = device->in_config->capture_length;
00557 breq.size = INPUT_BUFFER_SIZE;
00558 if(ioctl(jvideo_fd, BUZIOC_REQBUFS, &breq) < 0)
00559 perror("VDeviceBUZ::open_input BUZIOC_REQBUFS");
00560
00561
00562 if((input_buffer = (char*)mmap(0,
00563 breq.count * breq.size,
00564 PROT_READ,
00565 MAP_SHARED,
00566 jvideo_fd,
00567 0)) <= 0)
00568 perror("VDeviceBUZ::open_input mmap");
00569
00570
00571
00572 struct video_picture picture_params;
00573
00574 if(ioctl(jvideo_fd, VIDIOCGPICT, &picture_params) < 0)
00575 perror("VDeviceBUZ::set_picture VIDIOCGPICT");
00576 picture_params.brightness = brightness;
00577 picture_params.hue = hue;
00578 picture_params.colour = color;
00579 picture_params.contrast = contrast;
00580 picture_params.whiteness = whiteness;
00581
00582 if(ioctl(jvideo_fd, VIDIOCSPICT, &picture_params) < 0)
00583 perror("VDeviceBUZ::set_picture VIDIOCSPICT");
00584 if(ioctl(jvideo_fd, VIDIOCGPICT, &picture_params) < 0)
00585 perror("VDeviceBUZ::set_picture VIDIOCGPICT");
00586
00587
00588
00589
00590
00591 for(int i = 0; i < breq.count; i++)
00592 {
00593 if(ioctl(jvideo_fd, BUZIOC_QBUF_CAPT, &i) < 0)
00594 perror("VDeviceBUZ::open_input BUZIOC_QBUF_CAPT");
00595 }
00596
00597
00598 input_thread = new VDeviceBUZInput(this);
00599 input_thread->start();
00600
00601 return 0;
00602 }
00603
00604 int VDeviceBUZ::open_output_core(Channel *channel)
00605 {
00606
00607 total_loops = 0;
00608 output_number = 0;
00609 jvideo_fd = open(device->out_config->buz_out_device, O_RDWR);
00610 if(jvideo_fd <= 0)
00611 {
00612 perror("VDeviceBUZ::open_output");
00613 return 1;
00614 }
00615
00616
00617
00618 if(channel)
00619 {
00620 struct video_channel vch;
00621 vch.channel = channel->input;
00622 vch.norm = get_norm(channel->norm);
00623
00624 if(ioctl(jvideo_fd, VIDIOCSCHAN, &vch) < 0)
00625 perror("VDeviceBUZ::open_output_core VIDIOCSCHAN ");
00626 }
00627
00628 breq.count = 10;
00629 breq.size = INPUT_BUFFER_SIZE;
00630 if(ioctl(jvideo_fd, BUZIOC_REQBUFS, &breq) < 0)
00631 perror("VDeviceBUZ::open_output BUZIOC_REQBUFS");
00632 if((output_buffer = (char*)mmap(0,
00633 breq.count * breq.size,
00634 PROT_READ | PROT_WRITE,
00635 MAP_SHARED,
00636 jvideo_fd,
00637 0)) <= 0)
00638 perror("VDeviceBUZ::open_output mmap");
00639
00640 if(ioctl(jvideo_fd, BUZIOC_G_PARAMS, &bparm) < 0)
00641 perror("VDeviceBUZ::open_output BUZIOC_G_PARAMS");
00642
00643 bparm.decimation = 1;
00644 bparm.HorDcm = 1;
00645 bparm.field_per_buff = 2;
00646 bparm.TmpDcm = 1;
00647 bparm.VerDcm = 1;
00648 bparm.img_width = device->out_w;
00649 bparm.img_height = device->out_h / bparm.field_per_buff;
00650 bparm.img_x = 0;
00651 bparm.img_y = 0;
00652 bparm.odd_even = 0;
00653
00654 if(ioctl(jvideo_fd, BUZIOC_S_PARAMS, &bparm) < 0)
00655 perror("VDeviceBUZ::open_output BUZIOC_S_PARAMS");
00656
00657 return 0;
00658 }
00659
00660
00661
00662 int VDeviceBUZ::write_buffer(VFrame *frame, EDL *edl)
00663 {
00664
00665 tuner_lock->lock("VDeviceBUZ::write_buffer");
00666
00667 if(!jvideo_fd) open_output_core(0);
00668
00669 VFrame *ptr = 0;
00670 if(frame->get_color_model() != BC_COMPRESSED)
00671 {
00672 if(!temp_frame) temp_frame = new VFrame;
00673 if(!mjpeg)
00674 {
00675 mjpeg = mjpeg_new(device->out_w, device->out_h, 2);
00676 mjpeg_set_quality(mjpeg, device->quality);
00677 mjpeg_set_float(mjpeg, 0);
00678 }
00679 ptr = temp_frame;
00680 mjpeg_compress(mjpeg,
00681 frame->get_rows(),
00682 frame->get_y(),
00683 frame->get_u(),
00684 frame->get_v(),
00685 frame->get_color_model(),
00686 device->cpus);
00687 temp_frame->allocate_compressed_data(mjpeg_output_size(mjpeg));
00688 temp_frame->set_compressed_size(mjpeg_output_size(mjpeg));
00689 bcopy(mjpeg_output_buffer(mjpeg), temp_frame->get_data(), mjpeg_output_size(mjpeg));
00690 }
00691 else
00692 ptr = frame;
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702 if(device->out_config->buz_swap_fields)
00703 {
00704 long field2_offset = mjpeg_get_field2((unsigned char*)ptr->get_data(),
00705 ptr->get_compressed_size());
00706 long field2_len = ptr->get_compressed_size() - field2_offset;
00707 memcpy(output_buffer + output_number * breq.size,
00708 ptr->get_data() + field2_offset,
00709 field2_len);
00710 memcpy(output_buffer + output_number * breq.size +field2_len,
00711 ptr->get_data(),
00712 field2_offset);
00713 }
00714 else
00715 {
00716 bcopy(ptr->get_data(),
00717 output_buffer + output_number * breq.size,
00718 ptr->get_compressed_size());
00719 }
00720
00721 if(ioctl(jvideo_fd, BUZIOC_QBUF_PLAY, &output_number) < 0)
00722 perror("VDeviceBUZ::write_buffer BUZIOC_QBUF_PLAY");
00723
00724 output_number++;
00725 if(output_number >= breq.count)
00726 {
00727 output_number = 0;
00728 total_loops++;
00729 }
00730 tuner_lock->unlock();
00731
00732
00733 return 0;
00734 }
00735
00736 void VDeviceBUZ::new_output_buffer(VFrame *output,
00737 int colormodel)
00738 {
00739
00740 if(user_frame)
00741 {
00742 if(colormodel != user_frame->get_color_model())
00743 {
00744 delete user_frame;
00745 user_frame = 0;
00746 }
00747 }
00748
00749 if(!user_frame)
00750 {
00751 switch(colormodel)
00752 {
00753 case BC_COMPRESSED:
00754 user_frame = new VFrame;
00755 break;
00756 default:
00757 user_frame = new VFrame(0,
00758 device->out_w,
00759 device->out_h,
00760 colormodel,
00761 -1);
00762 break;
00763 }
00764 }
00765 user_frame->set_shm_offset(0);
00766 output = user_frame;
00767
00768 }
00769
00770
00771 ArrayList<int>* VDeviceBUZ::get_render_strategies()
00772 {
00773 return &render_strategies;
00774 }
00775