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