prevent popup deactivation while button_down
[goodguy/history.git] / cinelerra-5.0 / cinelerra / vdevicebuz.C
1 ;
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  * 
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * 
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  * 
20  */
21
22
23 #ifdef HAVE_VIDEO4LINUX
24
25 // ALPHA C++ can't compile 64 bit headers
26 #undef _LARGEFILE_SOURCE
27 #undef _LARGEFILE64_SOURCE
28 #undef _FILE_OFFSET_BITS
29
30 #include "assets.h"
31 #include "bcsignals.h"
32 #include "channel.h"
33 #include "chantables.h"
34 #include "condition.h"
35 #include "file.inc"
36 #include "mutex.h"
37 #include "picture.h"
38 #include "playbackconfig.h"
39 #include "preferences.h"
40 #include "recordconfig.h"
41 #include "strategies.inc"
42 #include "vdevicebuz.h"
43 #include "vframe.h"
44 #include "videoconfig.h"
45 #include "videodevice.h"
46
47 #include <errno.h>
48 #include <stdint.h>
49 #include <linux/kernel.h>
50 //#include <linux/videodev2.h>
51 #include <linux/videodev.h>
52 #include <fcntl.h>
53 #include <sys/ioctl.h>
54 #include <sys/mman.h>
55 #include <unistd.h>
56
57
58
59 #define READ_TIMEOUT 5000000
60
61
62 VDeviceBUZInput::VDeviceBUZInput(VDeviceBUZ *device)
63  : Thread(1, 1, 0)
64 {
65         this->device = device;
66         buffer = 0;
67         buffer_size = 0;
68         total_buffers = 0;
69         current_inbuffer = 0;
70         current_outbuffer = 0;
71         done = 0;
72         output_lock = new Condition(0, "VDeviceBUZInput::output_lock");
73         buffer_lock = new Mutex("VDeviceBUZInput::buffer_lock");
74 }
75
76 VDeviceBUZInput::~VDeviceBUZInput()
77 {
78         if(Thread::running())
79         {
80                 done = 1;
81                 Thread::cancel();
82                 Thread::join();
83         }
84
85         if(buffer)
86         {
87                 for(int i = 0; i < total_buffers; i++)
88                 {
89                         delete [] buffer[i];
90                 }
91                 delete [] buffer;
92                 delete [] buffer_size;
93         }
94         delete output_lock;
95         delete buffer_lock;
96 }
97
98 void VDeviceBUZInput::start()
99 {
100 // Create buffers
101         total_buffers = device->device->in_config->capture_length;
102         buffer = new char*[total_buffers];
103         buffer_size = new int[total_buffers];
104         bzero(buffer_size, sizeof(int) * total_buffers);
105         for(int i = 0; i < total_buffers; i++)
106         {
107                 buffer[i] = new char[INPUT_BUFFER_SIZE];
108         }
109
110         Thread::start();
111 }
112
113 void VDeviceBUZInput::run()
114 {
115     struct buz_sync bsync;
116
117 // Wait for frame
118         while(1)
119         {
120                 Thread::enable_cancel();
121                 if(ioctl(device->jvideo_fd, BUZIOC_SYNC, &bsync) < 0)
122                 {
123                         perror("VDeviceBUZInput::run BUZIOC_SYNC");
124                         if(done) return;
125                         Thread::disable_cancel();
126                 }
127                 else
128                 {
129                         Thread::disable_cancel();
130
131
132
133                         int new_buffer = 0;
134                         buffer_lock->lock("VDeviceBUZInput::run");
135 // Save only if the current buffer is free.
136                         if(!buffer_size[current_inbuffer])
137                         {
138                                 new_buffer = 1;
139 // Copy to input buffer
140                                 memcpy(buffer[current_inbuffer], 
141                                         device->input_buffer + bsync.frame * device->breq.size,
142                                         bsync.length);
143
144 // Advance input buffer number and decrease semaphore.
145                                 buffer_size[current_inbuffer] = bsync.length;
146                                 increment_counter(&current_inbuffer);
147                         }
148
149                         buffer_lock->unlock();
150
151                         if(ioctl(device->jvideo_fd, BUZIOC_QBUF_CAPT, &bsync.frame))
152                                 perror("VDeviceBUZInput::run BUZIOC_QBUF_CAPT");
153
154                         if(new_buffer) output_lock->unlock();
155                 }
156         }
157 }
158
159 void VDeviceBUZInput::get_buffer(char **ptr, int *size)
160 {
161 // Increase semaphore to wait for buffer.
162         int result = output_lock->timed_lock(READ_TIMEOUT, "VDeviceBUZInput::get_buffer");
163
164
165 // The driver has its own timeout routine but it doesn't work because
166 // because the tuner lock is unlocked and relocked with no delay.
167 //      int result = 0;
168 //      output_lock->lock("VDeviceBUZInput::get_buffer");
169
170         if(!result)
171         {
172 // Take over buffer table
173                 buffer_lock->lock("VDeviceBUZInput::get_buffer");
174                 *ptr = buffer[current_outbuffer];
175                 *size = buffer_size[current_outbuffer];
176                 buffer_lock->unlock();
177         }
178         else
179         {
180 //printf("VDeviceBUZInput::get_buffer 1\n");
181                 output_lock->unlock();
182         }
183 }
184
185 void VDeviceBUZInput::put_buffer()
186 {
187         buffer_lock->lock("VDeviceBUZInput::put_buffer");
188         buffer_size[current_outbuffer] = 0;
189         buffer_lock->unlock();
190         increment_counter(&current_outbuffer);
191 }
192
193 void VDeviceBUZInput::increment_counter(int *counter)
194 {
195         (*counter)++;
196         if(*counter >= total_buffers) *counter = 0;
197 }
198
199 void VDeviceBUZInput::decrement_counter(int *counter)
200 {
201         (*counter)--;
202         if(*counter < 0) *counter = total_buffers - 1;
203 }
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219 VDeviceBUZ::VDeviceBUZ(VideoDevice *device)
220  : VDeviceBase(device)
221 {
222         reset_parameters();
223         render_strategies.append(VRENDER_MJPG);
224         tuner_lock = new Mutex("VDeviceBUZ::tuner_lock");
225 }
226
227 VDeviceBUZ::~VDeviceBUZ()
228 {
229         close_all();
230         delete tuner_lock;
231 }
232
233 int VDeviceBUZ::reset_parameters()
234 {
235         jvideo_fd = 0;
236         input_buffer = 0;
237         output_buffer = 0;
238         frame_buffer = 0;
239         frame_size = 0;
240         frame_allocated = 0;
241         input_error = 0;
242         last_frame_no = 0;
243         temp_frame = 0;
244         user_frame = 0;
245         mjpeg = 0;
246         total_loops = 0;
247         output_number = 0;
248         input_thread = 0;
249         brightness = 32768;
250         hue = 32768;
251         color = 32768;
252         contrast = 32768;
253         whiteness = 32768;
254         return 0;
255 }
256
257 int VDeviceBUZ::close_input_core()
258 {
259         if(input_thread)
260         {
261                 delete input_thread;
262                 input_thread = 0;
263         }
264
265
266         if(device->r)
267         {
268                 if(jvideo_fd) close(jvideo_fd);
269                 jvideo_fd = 0;
270         }
271
272         if(input_buffer)
273         {
274                 if(input_buffer > 0)
275                         munmap(input_buffer, breq.count * breq.size);
276                 input_buffer = 0;
277         }
278         return 0;
279 }
280
281 int VDeviceBUZ::close_output_core()
282 {
283 //printf("VDeviceBUZ::close_output_core 1\n");
284         if(device->w)
285         {
286 //              if(ioctl(jvideo_fd, BUZIOC_QBUF_PLAY, &n) < 0)
287 //                      perror("VDeviceBUZ::close_output_core BUZIOC_QBUF_PLAY");
288                 if(jvideo_fd) close(jvideo_fd);
289                 jvideo_fd = 0;
290         }
291         if(output_buffer)
292         {
293                 if(output_buffer > 0)
294                         munmap(output_buffer, breq.count * breq.size);
295                 output_buffer = 0;
296         }
297         if(temp_frame)
298         {
299                 delete temp_frame;
300                 temp_frame = 0;
301         }
302         if(mjpeg)
303         {
304                 mjpeg_delete(mjpeg);
305                 mjpeg = 0;
306         }
307         if(user_frame)
308         {
309                 delete user_frame;
310                 user_frame = 0;
311         }
312 //printf("VDeviceBUZ::close_output_core 2\n");
313         return 0;
314 }
315
316
317 int VDeviceBUZ::close_all()
318 {
319 //printf("VDeviceBUZ::close_all 1\n");
320         close_input_core();
321 //printf("VDeviceBUZ::close_all 1\n");
322         close_output_core();
323 //printf("VDeviceBUZ::close_all 1\n");
324         if(frame_buffer) delete frame_buffer;
325 //printf("VDeviceBUZ::close_all 1\n");
326         reset_parameters();
327 //printf("VDeviceBUZ::close_all 2\n");
328         return 0;
329 }
330
331 #define COMPOSITE_TEXT "Composite"
332 #define SVIDEO_TEXT "S-Video"
333 #define BUZ_COMPOSITE 0
334 #define BUZ_SVIDEO 1
335
336 void VDeviceBUZ::get_inputs(ArrayList<Channel*> *input_sources)
337 {
338         Channel *new_source = new Channel;
339
340         new_source = new Channel;
341         strcpy(new_source->device_name, COMPOSITE_TEXT);
342         input_sources->append(new_source);
343
344         new_source = new Channel;
345         strcpy(new_source->device_name, SVIDEO_TEXT);
346         input_sources->append(new_source);
347 }
348
349 int VDeviceBUZ::open_input()
350 {
351         device->channel->use_norm = 1;
352         device->channel->use_input = 1;
353
354         device->picture->use_brightness = 1;
355         device->picture->use_contrast = 1;
356         device->picture->use_color = 1;
357         device->picture->use_hue = 1;
358         device->picture->use_whiteness = 1;
359
360 // Can't open input until after the channel is set
361         return 0;
362 }
363
364 int VDeviceBUZ::open_output()
365 {
366 // Can't open output until after the channel is set
367         return 0;
368 }
369
370 int VDeviceBUZ::set_channel(Channel *channel)
371 {
372         if(!channel) return 0;
373
374         tuner_lock->lock("VDeviceBUZ::set_channel");
375
376         if(device->r)
377         {
378                 close_input_core();
379                 open_input_core(channel);
380         }
381         else
382         {
383                 close_output_core();
384                 open_output_core(channel);
385         }
386
387         tuner_lock->unlock();
388
389
390         return 0;
391 }
392
393 int VDeviceBUZ::create_channeldb(ArrayList<Channel*> *channeldb)
394 {
395         return 0;
396 }
397
398 int VDeviceBUZ::set_picture(PictureConfig *picture)
399 {
400         this->brightness = (int)((float)picture->brightness / 100 * 32767 + 32768);
401         this->hue = (int)((float)picture->hue / 100 * 32767 + 32768);
402         this->color = (int)((float)picture->color / 100 * 32767 + 32768);
403         this->contrast = (int)((float)picture->contrast / 100 * 32767 + 32768);
404         this->whiteness = (int)((float)picture->whiteness / 100 * 32767 + 32768);
405
406
407         tuner_lock->lock("VDeviceBUZ::set_picture");
408         if(device->r)
409         {
410                 close_input_core();
411                 open_input_core(0);
412         }
413         else
414         {
415                 close_output_core();
416                 open_output_core(0);
417         }
418         tuner_lock->unlock();
419 // 
420 // 
421 // TRACE("VDeviceBUZ::set_picture 1");
422 //      tuner_lock->lock("VDeviceBUZ::set_picture");
423 // TRACE("VDeviceBUZ::set_picture 2");
424 // 
425 // 
426 // 
427 //      struct video_picture picture_params;
428 // // This call takes a long time in 2.4.22
429 //      if(ioctl(jvideo_fd, VIDIOCGPICT, &picture_params) < 0)
430 //              perror("VDeviceBUZ::set_picture VIDIOCGPICT");
431 //      picture_params.brightness = brightness;
432 //      picture_params.hue = hue;
433 //      picture_params.colour = color;
434 //      picture_params.contrast = contrast;
435 //      picture_params.whiteness = whiteness;
436 // // This call takes a long time in 2.4.22
437 //      if(ioctl(jvideo_fd, VIDIOCSPICT, &picture_params) < 0)
438 //              perror("VDeviceBUZ::set_picture VIDIOCSPICT");
439 //      if(ioctl(jvideo_fd, VIDIOCGPICT, &picture_params) < 0)
440 //              perror("VDeviceBUZ::set_picture VIDIOCGPICT");
441 // 
442 // 
443 // TRACE("VDeviceBUZ::set_picture 10");
444 // 
445 // 
446 //      tuner_lock->unlock();
447
448         return 0;
449 }
450
451 int VDeviceBUZ::get_norm(int norm)
452 {
453         switch(norm)
454         {
455         case NTSC:  return VIDEO_MODE_NTSC;
456         case PAL:   return VIDEO_MODE_PAL;
457         case SECAM: return VIDEO_MODE_SECAM;
458         }
459         printf("VDeviceBUZ::get_norm: unknown norm %d\n", norm);
460         return VIDEO_MODE_NTSC;
461 }
462
463 int VDeviceBUZ::read_buffer(VFrame *frame)
464 {
465         tuner_lock->lock("VDeviceBUZ::read_buffer");
466         if(!jvideo_fd) open_input_core(0);
467
468 // Get buffer from thread
469         char *buffer = 0;
470         int buffer_size = 0;
471         if(input_thread) 
472                 input_thread->get_buffer(&buffer, &buffer_size);
473
474         if(buffer)
475         {
476                 frame->allocate_compressed_data(buffer_size);
477                 frame->set_compressed_size(buffer_size);
478
479 // Transfer fields to frame
480                 if(device->odd_field_first)
481                 {
482                         long field2_offset = mjpeg_get_field2((unsigned char*)buffer, buffer_size);
483                         long field1_len = field2_offset;
484                         long field2_len = buffer_size - field2_offset;
485
486                         memcpy(frame->get_data(), buffer + field2_offset, field2_len);
487                         memcpy(frame->get_data() + field2_len, buffer, field1_len);
488                 }
489                 else
490                 {
491                         bcopy(buffer, frame->get_data(), buffer_size);
492                 }
493
494                 input_thread->put_buffer();
495                 tuner_lock->unlock();
496         }
497         else
498         {
499                 tuner_lock->unlock();
500                 Timer timer;
501 // Allow other threads to lock the tuner_lock under NPTL.
502                 timer.delay(100);
503         }
504
505
506         return 0;
507 }
508
509 int VDeviceBUZ::open_input_core(Channel *channel)
510 {
511         jvideo_fd = open(device->in_config->buz_in_device, O_RDONLY);
512
513         if(jvideo_fd <= 0)
514         {
515                 fprintf(stderr, "VDeviceBUZ::open_input %s: %s\n", 
516                         device->in_config->buz_in_device,
517                         strerror(errno));
518                 jvideo_fd = 0;
519                 return 1;
520         }
521
522 // Create input sources
523         get_inputs(&device->input_sources);
524
525 // Set current input source
526         if(channel)
527         {
528                 for(int i = 0; i < 2; i++)
529                 {
530                         struct video_channel vch;
531                         vch.channel = channel->input;
532                         vch.norm = get_norm(channel->norm);
533
534 //printf("VDeviceBUZ::open_input_core 2 %d %d\n", vch.channel, vch.norm);
535                         if(ioctl(jvideo_fd, VIDIOCSCHAN, &vch) < 0)
536                                 perror("VDeviceBUZ::open_input_core VIDIOCSCHAN ");
537                 }
538         }
539
540
541 // Throw away
542 //     struct video_capability vc;
543 //      if(ioctl(jvideo_fd, VIDIOCGCAP, &vc) < 0)
544 //              perror("VDeviceBUZ::open_input VIDIOCGCAP");
545
546 // API dependant initialization
547         if(ioctl(jvideo_fd, BUZIOC_G_PARAMS, &bparm) < 0)
548                 perror("VDeviceBUZ::open_input BUZIOC_G_PARAMS");
549
550         bparm.HorDcm = 1;
551         bparm.VerDcm = 1;
552         bparm.TmpDcm = 1;
553         bparm.field_per_buff = 2;
554         bparm.img_width = device->in_config->w;
555         bparm.img_height = device->in_config->h / bparm.field_per_buff;
556         bparm.img_x = 0;
557         bparm.img_y = 0;
558 //      bparm.APPn = 0;
559 //      bparm.APP_len = 14;
560         bparm.APP_len = 0;
561         bparm.odd_even = 0;
562     bparm.decimation = 0;
563     bparm.quality = device->quality;
564     bzero(bparm.APP_data, sizeof(bparm.APP_data));
565
566         if(ioctl(jvideo_fd, BUZIOC_S_PARAMS, &bparm) < 0)
567                 perror("VDeviceBUZ::open_input BUZIOC_S_PARAMS");
568
569 // printf("open_input %d %d %d %d %d %d %d %d %d %d %d %d\n", 
570 //              bparm.HorDcm,
571 //              bparm.VerDcm,
572 //              bparm.TmpDcm,
573 //              bparm.field_per_buff,
574 //              bparm.img_width,
575 //              bparm.img_height,
576 //              bparm.img_x,
577 //              bparm.img_y,
578 //              bparm.APP_len,
579 //              bparm.odd_even,
580 //      bparm.decimation,
581 //      bparm.quality);
582
583         breq.count = device->in_config->capture_length;
584         breq.size = INPUT_BUFFER_SIZE;
585         if(ioctl(jvideo_fd, BUZIOC_REQBUFS, &breq) < 0)
586                 perror("VDeviceBUZ::open_input BUZIOC_REQBUFS");
587
588 //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);
589         if((input_buffer = (char*)mmap(0, 
590                 breq.count * breq.size, 
591                 PROT_READ, 
592                 MAP_SHARED, 
593                 jvideo_fd, 
594                 0)) <= 0)
595                 perror("VDeviceBUZ::open_input mmap");
596
597
598 // Set picture quality
599         struct video_picture picture_params;
600 // This call takes a long time in 2.4.22
601         if(ioctl(jvideo_fd, VIDIOCGPICT, &picture_params) < 0)
602                 perror("VDeviceBUZ::set_picture VIDIOCGPICT");
603         picture_params.brightness = brightness;
604         picture_params.hue = hue;
605         picture_params.colour = color;
606         picture_params.contrast = contrast;
607         picture_params.whiteness = whiteness;
608 // This call takes a long time in 2.4.22
609         if(ioctl(jvideo_fd, VIDIOCSPICT, &picture_params) < 0)
610                 perror("VDeviceBUZ::set_picture VIDIOCSPICT");
611         if(ioctl(jvideo_fd, VIDIOCGPICT, &picture_params) < 0)
612                 perror("VDeviceBUZ::set_picture VIDIOCGPICT");
613
614
615 // Start capturing
616         int count = breq.count;
617         for(int i = 0; i < count; i++)
618         {
619                 if(ioctl(jvideo_fd, BUZIOC_QBUF_CAPT, &i) < 0)
620                         perror("VDeviceBUZ::open_input BUZIOC_QBUF_CAPT");
621         }
622
623
624         input_thread = new VDeviceBUZInput(this);
625         input_thread->start();
626 //printf("VDeviceBUZ::open_input_core 2\n");
627         return 0;
628 }
629
630 int VDeviceBUZ::open_output_core(Channel *channel)
631 {
632 //printf("VDeviceBUZ::open_output 1\n");
633         total_loops = 0;
634         output_number = 0;
635         jvideo_fd = open(device->out_config->buz_out_device, O_RDWR);
636         if(jvideo_fd <= 0)
637         {
638                 perror("VDeviceBUZ::open_output");
639                 return 1;
640         }
641
642
643 // Set current input source
644         if(channel)
645         {
646                 struct video_channel vch;
647                 vch.channel = channel->input;
648                 vch.norm = get_norm(channel->norm);
649
650                 if(ioctl(jvideo_fd, VIDIOCSCHAN, &vch) < 0)
651                         perror("VDeviceBUZ::open_output_core VIDIOCSCHAN ");
652         }
653
654         breq.count = 10;
655         breq.size = INPUT_BUFFER_SIZE;
656         if(ioctl(jvideo_fd, BUZIOC_REQBUFS, &breq) < 0)
657                 perror("VDeviceBUZ::open_output BUZIOC_REQBUFS");
658         if((output_buffer = (char*)mmap(0, 
659                 breq.count * breq.size, 
660                 PROT_READ | PROT_WRITE, 
661                 MAP_SHARED, 
662                 jvideo_fd, 
663                 0)) <= 0)
664                 perror("VDeviceBUZ::open_output mmap");
665
666         if(ioctl(jvideo_fd, BUZIOC_G_PARAMS, &bparm) < 0)
667                 perror("VDeviceBUZ::open_output BUZIOC_G_PARAMS");
668
669         bparm.decimation = 1;
670         bparm.HorDcm = 1;
671         bparm.field_per_buff = 2;
672         bparm.TmpDcm = 1;
673         bparm.VerDcm = 1;
674         bparm.img_width = device->out_w;
675         bparm.img_height = device->out_h / bparm.field_per_buff;
676         bparm.img_x = 0;
677         bparm.img_y = 0;
678         bparm.odd_even = 0;
679
680         if(ioctl(jvideo_fd, BUZIOC_S_PARAMS, &bparm) < 0)
681                 perror("VDeviceBUZ::open_output BUZIOC_S_PARAMS");
682 //printf("VDeviceBUZ::open_output 2\n");
683         return 0;
684 }
685
686
687
688 int VDeviceBUZ::write_buffer(VFrame *frame, EDL *edl)
689 {
690 //printf("VDeviceBUZ::write_buffer 1\n");
691         tuner_lock->lock("VDeviceBUZ::write_buffer");
692
693         if(!jvideo_fd) open_output_core(0);
694
695         VFrame *ptr = 0;
696         if(frame->get_color_model() != BC_COMPRESSED)
697         {
698                 if(!temp_frame) temp_frame = new VFrame;
699                 if(!mjpeg)
700                 {
701                         mjpeg = mjpeg_new(device->out_w, device->out_h, 2);
702                         mjpeg_set_quality(mjpeg, device->quality);
703                         mjpeg_set_float(mjpeg, 0);
704                 }
705                 ptr = temp_frame;
706                 mjpeg_compress(mjpeg, 
707                         frame->get_rows(), 
708                         frame->get_y(), 
709                         frame->get_u(), 
710                         frame->get_v(),
711                         frame->get_color_model(),
712                         device->cpus);
713                 temp_frame->allocate_compressed_data(mjpeg_output_size(mjpeg));
714                 temp_frame->set_compressed_size(mjpeg_output_size(mjpeg));
715                 bcopy(mjpeg_output_buffer(mjpeg), temp_frame->get_data(), mjpeg_output_size(mjpeg));
716         }
717         else
718                 ptr = frame;
719
720 // Wait for frame to become available
721 // Caused close_output_core to lock up.
722 //      if(total_loops >= 1)
723 //      {
724 //              if(ioctl(jvideo_fd, BUZIOC_SYNC, &output_number) < 0)
725 //                      perror("VDeviceBUZ::write_buffer BUZIOC_SYNC");
726 //      }
727
728         if(device->out_config->buz_swap_fields)
729         {
730                 long field2_offset = mjpeg_get_field2((unsigned char*)ptr->get_data(), 
731                         ptr->get_compressed_size());
732                 long field2_len = ptr->get_compressed_size() - field2_offset;
733                 memcpy(output_buffer + output_number * breq.size, 
734                         ptr->get_data() + field2_offset, 
735                         field2_len);
736                 memcpy(output_buffer + output_number * breq.size +field2_len,
737                         ptr->get_data(), 
738                         field2_offset);
739         }
740         else
741         {
742                 bcopy(ptr->get_data(), 
743                         output_buffer + output_number * breq.size, 
744                         ptr->get_compressed_size());
745         }
746
747         if(ioctl(jvideo_fd, BUZIOC_QBUF_PLAY, &output_number) < 0)
748                 perror("VDeviceBUZ::write_buffer BUZIOC_QBUF_PLAY");
749
750         output_number++;
751         if(output_number >= (int)breq.count)
752         {
753                 output_number = 0;
754                 total_loops++;
755         }
756         tuner_lock->unlock();
757 //printf("VDeviceBUZ::write_buffer 2\n");
758
759         return 0;
760 }
761
762 void VDeviceBUZ::new_output_buffer(VFrame *output,
763         int colormodel)
764 {
765 //printf("VDeviceBUZ::new_output_buffer 1 %d\n", colormodel);
766         if(user_frame)
767         {
768                 if(colormodel != user_frame->get_color_model())
769                 {
770                         delete user_frame;
771                         user_frame = 0;
772                 }
773         }
774
775         if(!user_frame)
776         {
777                 switch(colormodel)
778                 {
779                         case BC_COMPRESSED:
780                                 user_frame = new VFrame;
781                                 break;
782                         default:
783                                 user_frame = new VFrame(0,
784                                         -1,
785                                         device->out_w,
786                                         device->out_h,
787                                         colormodel,
788                                         -1);
789                                 break;
790                 }
791         }
792 //      user_frame->set_shm_offset(0);
793         output = user_frame;
794 //printf("VDeviceBUZ::new_output_buffer 2\n");
795 }
796
797
798 ArrayList<int>* VDeviceBUZ::get_render_strategies()
799 {
800         return &render_strategies;
801 }
802
803
804 #endif // HAVE_VIDEO4LINUX
805
806