Credit Andrew - improve in-tree documentation
[goodguy/cinelerra.git] / cinelerra / devicempeginput.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
24
25
26 #include "audiompeg.h"
27 #include "channel.h"
28 #include "chantables.h"
29 #include "condition.h"
30 #include "cstrdup.h"
31 #include "devicempeginput.h"
32 #include "edl.h"
33 #include "edlsession.h"
34 #include "filempeg.h"
35 #include "linklist.h"
36 #include "mwindow.h"
37 #include "preferences.h"
38 #include "picture.h"
39 #include "recordconfig.h"
40 #include "vdevicempeg.h"
41
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <stdint.h>
45 #include <unistd.h>
46 #include <string.h>
47 #include <errno.h>
48 #include <fcntl.h>
49 #include <sys/ioctl.h>
50 #include <sys/mman.h>
51 #ifdef HAVE_VIDEO4LINUX2
52 #include <linux/videodev2.h>
53 #endif
54
55 Condition DeviceMPEGInput::in_mpeg_lock(1,"DeviceMPEGInput::in_mpeg_lock");
56 DeviceMPEGList DeviceMPEGInput::in_mpeg;
57
58 DeviceMPEGInput::DeviceMPEGInput(const char *name, int no)
59  : Garbage("DeviceMPEGInput")
60 {
61 //printf("new DeviceMPEGInput\n");
62         reset();
63         dev_name = cstrdup(name);
64         device_number = no;
65         decoder_lock = new Mutex("DeviceMPEGInput::decoder_lock", 0);
66         video_lock = new Mutex("DeviceMPEGInput::video_lock", 0);
67         audio_lock = new Mutex("DeviceMPEGInput::audio_lock", 0);
68         toc_builder = new DeviceMPEG_TOC_Builder(this);
69 }
70
71 DeviceMPEGInput::~DeviceMPEGInput()
72 {
73 //printf("delete DeviceMPEGInput\n");
74         delete toc_builder;
75         delete src;
76         delete toc;
77         delete channel;
78         delete decoder_lock;
79         delete video_lock;
80         delete audio_lock;
81         delete [] dev_name;
82 }
83
84
85 void DeviceMPEGInput::reset()
86 {
87         dev_name = 0;
88         device_number = 0;
89         video_device = 0;
90         audio_device = 0;
91         channel = 0;
92         decoder_lock = 0;
93         video_lock = 0;
94         audio_lock = 0;
95         src = 0;
96         toc = 0;
97         toc_builder = 0;
98         toc_pos = 0;
99         record_fd = -1;
100         total_buffers = 0;
101         device_buffers = 0;
102         buffer_valid = 0;
103         streamon = 0;
104         color_model = -1;
105         audio_inited = 0;
106         video_inited = 0;
107         captioning = -1;
108         audio_stream = video_stream = -1;
109         width = height = 0;
110         framerate = 0.;
111         channels = sample_bits = samplerate = 0;
112         total_vstreams = total_achannels = 0;
113 }
114
115 DeviceMPEGInput* DeviceMPEGInput::get_mpeg_device(
116         DeviceMPEGInput* (*new_device)(const char *name, int no),
117         const char *name, int no)
118 {
119         DeviceMPEGInput *current = in_mpeg.first;
120         while( current ) {
121                 if( current->device_number != no ) continue;
122                 if( !strcmp(current->dev_name, name) ) break;
123                 current = NEXT;
124         }
125         if( !current )
126         {
127                 current = new_device(name, no);
128                 in_mpeg.append(current);
129         }
130         else
131                 current->add_user();
132         return current;
133 }
134
135
136 DeviceMPEGInput* DeviceMPEGInput::get_mpeg_video(VideoDevice *video_device,
137         DeviceMPEGInput* (*new_device)(const char *name, int no),
138         const char *name, int no)
139 {
140 //printf("get_mpeg_video\n");
141         in_mpeg_lock.lock("DeviceMPEGInput::get_mpeg_video");
142         DeviceMPEGInput* device = get_mpeg_device(new_device, name, no);
143         if( !device->video_device )
144                 device->video_device = video_device;
145         else
146                 device = 0;
147         in_mpeg_lock.unlock();
148         return device;
149 }
150
151 DeviceMPEGInput* DeviceMPEGInput::get_mpeg_audio(AudioDevice *audio_device,
152         DeviceMPEGInput* (*new_device)(const char *name, int no),
153         const char *name, int no)
154 {
155 //printf("get_mpeg_audio\n");
156         in_mpeg_lock.lock("DeviceMPEGInput::get_mpeg_audio");
157         DeviceMPEGInput* device = get_mpeg_device(new_device, name, no);
158         if( !device->audio_device )
159                 device->audio_device = audio_device;
160         else
161                 device = 0;
162         in_mpeg_lock.unlock();
163         return device;
164 }
165
166 void DeviceMPEGInput::put_mpeg_video()
167 {
168 //printf("put_mpeg_video\n");
169         in_mpeg_lock.lock("DeviceMPEGInput::put_mpeg_video");
170         video_device = 0;
171         remove_user();
172         in_mpeg_lock.unlock();
173 }
174
175 void DeviceMPEGInput::put_mpeg_audio()
176 {
177 //printf("put_mpeg_audio\n");
178         in_mpeg_lock.lock("DeviceMPEGInput::put_mpeg_audio");
179         audio_device = 0;
180         remove_user();
181         in_mpeg_lock.unlock();
182 }
183
184
185 MWindow *DeviceMPEGInput::get_mwindow()
186 {
187         in_mpeg_lock.lock("DeviceMPEGInput::get_mwindow");
188         MWindow *mwindow = video_device ? video_device->mwindow :
189                   audio_device ? audio_device->mwindow : 0;
190         in_mpeg_lock.unlock();
191         return mwindow;
192 }
193
194 int DeviceMPEGInput::get_stream(int reopen)
195 {
196         int ret = 0;
197         if( src ) {
198 //printf("DeviceMPEGInput::get_stream delete src %p\n",src);
199                 delete src;  src = 0;
200                 audio_stream = video_stream = -1;
201         }
202         if( reopen ) close_dev();
203         if( !channel ) ret = 1;
204         if( !ret ) ret = open_dev(color_model);
205         if( !ret ) ret = status_dev();
206         if( !ret ) ret = has_signal() ? 0 : 1;
207         if( !ret ) {
208 //struct stat st; fstat(mpeg_fd(),&st); printf("stat %08x/%08x\n",(int)st.st_dev,(int)st.st_rdev);
209 //              src = new zmpeg3_t(mpeg_fd(), ret, !st.st_rdev ? 0 : ZIO_THREADED+ZIO_NONBLOCK);
210                 src = new zmpeg3_t(mpeg_fd(), ret, ZIO_THREADED+ZIO_NONBLOCK);
211 //printf("DeviceMPEGInput::get_stream new src %p\n",src);
212                 if( !ret && channel->audio_stream >= src->total_astreams() ) ret = 1;
213                 if( !ret && channel->video_stream >= src->total_vstreams() ) ret = 1;
214                 if( !ret && record_fd >= 0 ) src->start_record(record_fd, 0);
215                 if( !ret ) {
216                         audio_stream = channel->audio_stream;
217                         video_stream = channel->video_stream;
218                         MWindow *mwindow = get_mwindow();
219                         int cpus = mwindow ? mwindow->preferences->real_processors : 1;
220                         src->set_cpus(cpus);
221                         src->show_subtitle(video_stream, captioning);
222                         height = src->video_height(video_stream);
223                         if( height < 0 ) height = 0;
224                         width = src->video_width(video_stream);
225                         if( width < 0 ) width = 0;
226                         framerate = src->frame_rate(video_stream);
227                         if( framerate < 0. ) framerate = 0.;
228                         channels = src->audio_channels(audio_stream);
229                         if( channels < 0 ) channels = 0;
230                         samplerate = src->sample_rate(audio_stream);
231                         if( samplerate < 0 ) samplerate = 0;
232                         sample_bits = sizeof(short)*8;
233                         int dev_cmodel = src->colormodel(video_stream);
234                         printf("mpeg video %dx%d @%6.2ffps %s  "
235                                 "audio %dchs, %d rate %d bits\n",
236                                 height, width, framerate,
237                                 FileMPEG::zmpeg3_cmdl_name(dev_cmodel),
238                                 channels, samplerate, sample_bits);
239                         total_vstreams = src->total_vstreams();
240                         total_achannels = 0;
241                         int total_astreams = src->total_astreams();
242                         for( int stream=0; stream<total_astreams; ++stream )
243                                 total_achannels +=  src->audio_channels(stream);
244                 }
245                 else {
246                         fprintf(stderr,"DeviceMPEGInput::get_stream open failed (%d)\n", ret);
247                         delete src;  src = 0;
248                 }
249         }
250         if( ret ) close_dev();
251         return ret;
252 }
253
254 int DeviceMPEGInput::src_stream(Mutex *stream)
255 {
256         int ret = 0;
257         decoder_lock->lock();
258         if( !src ) {
259                 audio_lock->lock();
260                 video_lock->lock();
261                 ret = get_stream();
262                 video_lock->unlock();
263                 audio_lock->unlock();
264         }
265         if( !ret && stream ) stream->lock();
266         if( ret || stream ) decoder_lock->unlock();
267         return ret;
268 }
269
270 zmpeg3_t *
271 DeviceMPEGInput::src_lock()
272 {
273         decoder_lock->lock();
274         if( src ) return src;
275         decoder_lock->unlock();
276         return 0;
277 }
278
279 void DeviceMPEGInput::src_unlock()
280 {
281         decoder_lock->unlock();
282 }
283
284 int DeviceMPEGInput::get_dev_cmodel(int color_model)
285 {
286         int result = FileMPEG::zmpeg3_cmdl(color_model);
287         if( result < 0 )
288                 printf("DeviceMPEGInput::get_dev_cmodel: unknown color_model for libzmpeg3\n");
289         return result;
290 }
291
292 int DeviceMPEGInput::colormodel()
293 {
294         return color_model>=0 ? color_model : BC_YUV420P;
295 }
296
297 int DeviceMPEGInput::read_buffer(VFrame *frame)
298 {
299         int result = 1;
300         if( !video_inited )
301         {
302                 color_model = frame->get_color_model();
303                 if( (result=open_dev(color_model)) ) return result;
304                 if( (result=src_stream()) ) return result;
305                 int width = video_width();
306                 int height = video_height();
307                 double rate = video_framerate();
308                 video_device->auto_update(rate, width, height);
309                 video_device->capturing = 1;
310                 src_unlock();
311                 video_inited = 1;
312                 return -1;
313         }
314         int dev_cmodel = get_dev_cmodel(color_model);
315         if( dev_cmodel >= 0 ) {
316                 int w = frame->get_w();
317                 int h = frame->get_h();
318                 uint8_t *data = frame->get_data();
319                 int bpl = frame->get_bytes_per_line();
320                 int uvs = 0;
321                 switch( dev_cmodel ) {
322                 case zmpeg3_t::cmdl_YUV420P: uvs = 2;  break;
323                 case zmpeg3_t::cmdl_YUV422P: uvs = 1;  break;
324                 default: break;
325                 }
326                 int uvw = !uvs ? 0 : bpl / 2;
327                 int uvh = !uvs ? 0 : 2*h / uvs;
328                 uint8_t *rows[h + uvh], *rp = data;
329                 int n = 0;
330                 for( int i=0; i<h; ++i, rp+=bpl ) rows[n++] = rp;
331                 for( int i=0; i<uvh; ++i, rp+=uvw ) rows[n++] = rp;
332                 if( !src_stream(video_lock) ) {
333                         double timestamp = src->get_video_time(video_stream);
334                         frame->set_timestamp(timestamp);
335                         result = src->read_frame(&rows[0],
336                                 0,0, width,height,
337                                 w,h, dev_cmodel, video_stream);
338                         video_lock->unlock();
339                 }
340                 if( result )
341                         set_channel(channel);
342         }
343         return result;
344 }
345
346 int DeviceMPEGInput::read_audio(char *data, int size)
347 {
348         int result = -1;
349         if( !audio_inited )
350         {
351                 if( (result=src_stream()) ) return result;
352                 int samplerate = audio_sample_rate();
353                 int channels = audio_channels();
354                 int bits = audio_sample_bits();
355 //printf("DeviceMPEGInput::read_audio activate  ch %d, rate %d, bits %d\n",
356 //  channels, samplerate, bits);
357                 audio_device->auto_update(channels, samplerate, bits);
358                 src_unlock();
359                 audio_inited = 1;
360                 return -1;
361         }
362         int frame = (sample_bits * channels) / 8;
363         if( size > 0 && frame > 0 && audio_stream >= 0 &&
364                         !src_stream(audio_lock) ) {
365                 result = 0;
366                 short *sdata = (short*)data;
367                 int samples = size / frame;
368                 short bfr[samples];
369                 int chans = channels;
370                 for( int ch=0; ch<chans; ++ch ) {
371                         int ret = ch == 0 ?
372                 src->read_audio(&bfr[0], ch, samples, audio_stream) :
373                 src->reread_audio(&bfr[0], ch, samples, audio_stream);
374                         if( !ret ) {
375                                 int k = ch;
376                                 for( int i=0; i<samples; ++i,k+=chans )
377                                         sdata[k] = bfr[i];
378                         }
379                         else {
380                                 int k = ch;
381                                 for( int i=0; i<samples; ++i,k+=chans )
382                                         sdata[k] = 0;
383                                 result = -1;
384                         }
385                 }
386                 audio_lock->unlock();
387         }
388         return result;
389 }
390
391 int DeviceMPEGInput::set_channel(Channel *channel)
392 {
393 //printf("DeviceMPEGInput::set_channel: enter %s\n",!channel ? "close" :
394 //  channel == this->channel ? "reset" : channel->title);
395         decoder_lock->lock();
396         audio_lock->lock();
397         video_lock->lock();
398         Channel *new_channel = 0;
399         if( channel ) {
400                 new_channel = new Channel;
401                 new_channel->copy_settings(channel);
402                 new_channel->copy_usage(channel);
403         }
404         delete this->channel;
405         this->channel = new_channel;
406         audio_reset();
407         video_reset();
408         int ret = get_stream(1);
409         video_lock->unlock();
410         audio_lock->unlock();
411         decoder_lock->unlock();
412 //printf("DeviceMPEGInput::set_channel: exit %d\n",has_lock);
413         return !ret && !status_dev() && has_signal() ? 0 : 1;
414 }
415
416 void DeviceMPEGInput::set_captioning(int strk)
417 {
418         decoder_lock->lock("DeviceMPEGInput::set_captioning");
419         captioning = strk;
420         if( src && video_stream >= 0 )
421                 src->show_subtitle(video_stream, strk);
422         decoder_lock->unlock();
423 }
424
425 int DeviceMPEGInput::drop_frames(int frames)
426 {
427         decoder_lock->lock("DeviceMPEGInput::drop_frames");
428         double result = -1.;
429         if( src && video_stream >= 0 )
430                 result = src->drop_frames(frames,video_stream);
431         decoder_lock->unlock();
432         return result;
433 }
434
435 double DeviceMPEGInput::audio_timestamp()
436 {
437         decoder_lock->lock("DeviceMPEGInput::audio_timestamp");
438         double result = -1.;
439         if( src && audio_stream >= 0 )
440                 result = src->get_audio_time(audio_stream);
441         decoder_lock->unlock();
442         return result;
443 }
444
445 double DeviceMPEGInput::video_timestamp()
446 {
447         decoder_lock->lock("DeviceMPEGInput::video_timestamp");
448         double ret = -1.;
449         if( src && video_stream >= 0 )
450                 ret = src->get_video_time(video_stream);
451         decoder_lock->unlock();
452         return ret;
453 }
454
455 int DeviceMPEGInput::start_toc(const char *path, const char *toc_path)
456 {
457         if( !src || toc ) return -1;
458         toc = src->start_toc(path, toc_path);
459         toc_pos = 0;
460         toc_builder->start();
461         return toc ? 0 : 1;
462 }
463
464 int DeviceMPEGInput::tick_toc()
465 {
466         if( record_fd < 0 || !src || !toc ) return 1;
467         while( toc_pos < src->record_position() )
468                 toc->do_toc(&toc_pos);
469         return 0;
470 }
471
472 int DeviceMPEGInput::start_record(int fd, int bsz)
473 {
474         record_fd = fd;
475         return src ? src->start_record(fd, bsz) : -1;
476 }
477
478 int DeviceMPEGInput::stop_record()
479 {
480         int ret = src ? src->stop_record() : -1;
481         if( toc ) {
482                 toc_builder->stop(1);
483                 toc->stop_toc();
484                 toc = 0;
485         }
486         record_fd = -1;
487         return ret;
488 }
489
490 int DeviceMPEGInput::subchannel_count()
491 {
492 #ifdef HAVE_DVB
493         return src ? src->dvb.channel_count() : 0;
494 #else
495         return 0;
496 #endif
497 }
498
499 int DeviceMPEGInput::subchannel_definition(int subchan, char *name,
500         int &major, int &minor, int &total_astreams, int &total_vstreams)
501 {
502 #ifdef HAVE_DVB
503         int result = src != 0 ? 0 : -1;
504         if( !result ) result = src->dvb.get_channel(subchan, major, minor);
505         if( !result ) result = src->dvb.get_station_id(subchan, &name[0]);
506         if( !result ) result = src->dvb.total_astreams(subchan, total_astreams);
507         if( !result ) result = src->dvb.total_vstreams(subchan, total_vstreams);
508         return result;
509 #else
510         return -1;
511 #endif
512 }
513
514 int DeviceMPEGInput::subchannel_video_stream(int subchan, int vstream)
515 {
516 #ifdef HAVE_DVB
517         int result = src != 0 ? 0 : -1;
518         if( !result && src->dvb.vstream_number(subchan, vstream, result) )
519                 result = -1;
520         return result;
521 #else
522         return -1;
523 #endif
524 }
525
526 int DeviceMPEGInput::subchannel_audio_stream(int subchan, int astream, char *enc)
527 {
528 #ifdef HAVE_DVB
529         int result = src != 0 ? 0 : -1;
530         if( src && src->dvb.astream_number(subchan, astream, result, enc) ) {
531                 enc[0] = 0; result = -1;
532         }
533         return result;
534 #else
535         return -1;
536 #endif
537 }
538
539 int DeviceMPEGInput::get_video_pid(int track)
540 {
541         return !src ? -1 : src->video_pid(track);
542 }
543
544 int DeviceMPEGInput::get_video_info(int track, int &pid, double &framerate,
545                 int &width, int &height, char *title)
546 {
547         //caller of callback holds decoder_lock;
548         if( !src ) return 1;
549         pid = src->video_pid(track);
550         framerate = src->frame_rate(track);
551         width = src->video_width(track);
552         height = src->video_height(track);
553         if( !title ) return 0;
554         *title = 0;
555         int elements = src->dvb.channel_count();
556         for( int n=0; n<elements; ++n ) {
557                 int major, minor, total_vstreams, vstream, vidx;
558                 if( src->dvb.get_channel(n, major, minor) ) continue;
559                 if( src->dvb.total_vstreams(n,total_vstreams) ) continue;
560                 for( vidx=0; vidx<total_vstreams; ++vidx ) {
561                         if( src->dvb.vstream_number(n,vidx,vstream) ) continue;
562                         if( vstream < 0 ) continue;
563                         if( vstream == track ) {
564                                 sprintf(title, "%3d.%-3d", major, minor);
565                                 return 0;
566                         }
567                 }
568         }
569         return 0;
570 }
571
572 int DeviceMPEGInput::get_thumbnail(int stream, int64_t &position,
573                 unsigned char *&thumbnail, int &ww, int &hh)
574 {
575         if( !src ) return 1;
576         return src->get_thumbnail(stream, position, thumbnail, ww, hh);
577 }
578
579 int DeviceMPEGInput::set_skimming(int track, int skim, skim_fn fn, void *vp)
580 {
581         if( !src ) return 1;
582         return !fn ? src->set_thumbnail_callback(track, 0, 0, 0, 0) :
583                 src->set_thumbnail_callback(track, skim, 1, fn, vp);
584 }
585
586
587 Channel *DeviceMPEGInput::add_channel( ArrayList<Channel*> *channeldb, char *name,
588         int element, int major, int minor, int vstream, int astream, char *enc)
589 {
590         Channel *ch = new Channel;
591         ch->copy_settings(channel);
592         sprintf(ch->title,"%d.%d %s", major, minor, &name[0]);
593         sprintf(ch->device_name,"%d", get_channel());
594         if( astream >= 0 && enc && enc[0] ) {
595                 char *cp = ch->title;  cp += strlen(cp);
596                 sprintf(cp," (%s)",&enc[0]);
597         }
598         ch->element = element;
599         ch->video_stream = vstream;
600         ch->audio_stream = astream;
601         channeldb->append(ch);
602         return ch;
603 }
604
605 //printf("   channel %s\n",channel->title);
606 int DeviceMPEGInput::get_channeldb(ArrayList<Channel*> *channeldb)
607 {
608 //printf(" get channel record\n");
609         int count = subchannel_count();
610         for( int subchan=0; subchan<count; ++subchan ) {
611                 char name[16], enc[8];
612                 int vstream = -1, video_stream = -1;
613                 int astream = -1, audio_stream = -1;
614                 int major, minor, total_astreams, total_vstreams;
615                 if( subchannel_definition(subchan,&name[0],
616                         major, minor, total_astreams, total_vstreams)) continue;
617                 if( total_astreams > 1 && total_vstreams > 1 )
618                         printf(_("DeviceMPEGInput::get_channeldb::element %d"
619                                 " (id %d.%d) has %d/%d video/audio streams\n"),
620                                 subchan, major, minor, total_vstreams, total_astreams);
621                 if( total_vstreams > 1 && total_astreams > 0 && (audio_stream =
622                         subchannel_audio_stream(subchan, astream=0, enc)) >= 0 ) {
623                         if( total_astreams > 1 )
624                                 printf(_("  only first audio stream will be used\n"));
625                         for( int vstream=0; vstream<total_vstreams; ++vstream ) {
626                                 int video_stream = subchannel_video_stream(subchan, vstream);
627                                 if( video_stream < 0 ) continue;
628                                 Channel *ch = add_channel(channeldb, name, subchan,
629                                         major, minor, video_stream, audio_stream, enc);
630                                 char *cp = ch->title;  cp += strlen(cp);
631                                 sprintf(cp," v%d",vstream+1);
632                         }
633                         continue;
634                 }
635                 if( total_astreams > 1 && total_vstreams > 0 && (video_stream =
636                         subchannel_video_stream(subchan, vstream=0)) >= 0 ) {
637                         if( total_vstreams > 1 )
638                                 printf(_("  only first video stream will be used\n"));
639                         for( int astream=0; astream<total_astreams; ++astream ) {
640                                 int audio_stream = subchannel_audio_stream(subchan, astream, enc);
641                                 if( audio_stream < 0 ) continue;
642                                 Channel *ch = add_channel(channeldb, name, subchan,
643                                         major, minor, video_stream, audio_stream, enc);
644                                 char *cp = ch->title;  cp += strlen(cp);
645                                 sprintf(cp," a%d",astream+1);
646                         }
647                         continue;
648                 }
649                 if( total_astreams > 0 || total_vstreams > 0 ) {
650                         astream = vstream = -1;
651                         video_stream = !total_vstreams ? -1 :
652                                 subchannel_video_stream(subchan, vstream = 0);
653                         audio_stream = !total_astreams ? -1 :
654                                 subchannel_audio_stream(subchan, astream = 0, enc);
655                         add_channel(channeldb, name, subchan,
656                                 major, minor, video_stream, audio_stream, enc);
657                 }
658         }
659         return 0;
660 }
661
662 int DeviceMPEGInput::create_channeldb(ArrayList<Channel*> *channeldb)
663 {
664         int ret = 1;
665         if( !src_stream() ) {
666                 ret = get_channeldb(channeldb);
667                 src_unlock();
668         }
669         return ret;
670 }
671
672 DeviceMPEG_TOC_Builder::
673 DeviceMPEG_TOC_Builder(DeviceMPEGInput *mpeg_dev)
674  : Thread(1, 0, 0)
675 {
676         this->mpeg_dev = mpeg_dev;
677         done = -1;
678 }
679
680 DeviceMPEG_TOC_Builder::
681 ~DeviceMPEG_TOC_Builder()
682 {
683         stop();
684 }
685
686
687 void DeviceMPEG_TOC_Builder::
688 stop(int wait)
689 {
690         if( !done ) {
691                 done = 1;
692                 if( !wait ) Thread::cancel();
693         }
694         Thread::join();
695 }
696
697 void DeviceMPEG_TOC_Builder::
698 start()
699 {
700         done = 0;
701         Thread::start();
702 }
703
704 void DeviceMPEG_TOC_Builder::
705 run()
706 {
707         Thread::enable_cancel();
708
709         while( !done ) {
710                 Thread::disable_cancel();
711                 mpeg_dev->tick_toc();
712                 Thread::enable_cancel();
713                 sleep(1);
714         }
715
716         Thread::disable_cancel();
717         mpeg_dev->tick_toc();
718         done = -1;
719 }
720