4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
26 #include "audiompeg.h"
28 #include "chantables.h"
29 #include "condition.h"
31 #include "devicempeginput.h"
33 #include "edlsession.h"
37 #include "preferences.h"
39 #include "recordconfig.h"
40 #include "vdevicempeg.h"
49 #include <sys/ioctl.h>
51 #ifdef HAVE_VIDEO4LINUX2
52 #include <linux/videodev2.h>
55 Condition DeviceMPEGInput::in_mpeg_lock(1,"DeviceMPEGInput::in_mpeg_lock");
56 DeviceMPEGList DeviceMPEGInput::in_mpeg;
58 DeviceMPEGInput::DeviceMPEGInput(const char *name, int no)
59 : Garbage("DeviceMPEGInput")
61 //printf("new DeviceMPEGInput\n");
63 dev_name = cstrdup(name);
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);
71 DeviceMPEGInput::~DeviceMPEGInput()
73 //printf("delete DeviceMPEGInput\n");
85 void DeviceMPEGInput::reset()
108 audio_stream = video_stream = -1;
111 channels = sample_bits = samplerate = 0;
112 total_vstreams = total_achannels = 0;
115 DeviceMPEGInput* DeviceMPEGInput::get_mpeg_device(
116 DeviceMPEGInput* (*new_device)(const char *name, int no),
117 const char *name, int no)
119 DeviceMPEGInput *current = in_mpeg.first;
121 if( current->device_number != no ) continue;
122 if( !strcmp(current->dev_name, name) ) break;
127 current = new_device(name, no);
128 in_mpeg.append(current);
136 DeviceMPEGInput* DeviceMPEGInput::get_mpeg_video(VideoDevice *video_device,
137 DeviceMPEGInput* (*new_device)(const char *name, int no),
138 const char *name, int no)
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;
147 in_mpeg_lock.unlock();
151 DeviceMPEGInput* DeviceMPEGInput::get_mpeg_audio(AudioDevice *audio_device,
152 DeviceMPEGInput* (*new_device)(const char *name, int no),
153 const char *name, int no)
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;
162 in_mpeg_lock.unlock();
166 void DeviceMPEGInput::put_mpeg_video()
168 //printf("put_mpeg_video\n");
169 in_mpeg_lock.lock("DeviceMPEGInput::put_mpeg_video");
172 in_mpeg_lock.unlock();
175 void DeviceMPEGInput::put_mpeg_audio()
177 //printf("put_mpeg_audio\n");
178 in_mpeg_lock.lock("DeviceMPEGInput::put_mpeg_audio");
181 in_mpeg_lock.unlock();
185 MWindow *DeviceMPEGInput::get_mwindow()
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();
194 int DeviceMPEGInput::get_stream(int reopen)
198 //printf("DeviceMPEGInput::get_stream delete src %p\n",src);
200 audio_stream = video_stream = -1;
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;
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);
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;
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();
241 int total_astreams = src->total_astreams();
242 for( int stream=0; stream<total_astreams; ++stream )
243 total_achannels += src->audio_channels(stream);
246 fprintf(stderr,"DeviceMPEGInput::get_stream open failed (%d)\n", ret);
250 if( ret ) close_dev();
254 int DeviceMPEGInput::src_stream(Mutex *stream)
257 decoder_lock->lock();
262 video_lock->unlock();
263 audio_lock->unlock();
265 if( !ret && stream ) stream->lock();
266 if( ret || stream ) decoder_lock->unlock();
271 DeviceMPEGInput::src_lock()
273 decoder_lock->lock();
274 if( src ) return src;
275 decoder_lock->unlock();
279 void DeviceMPEGInput::src_unlock()
281 decoder_lock->unlock();
284 int DeviceMPEGInput::get_dev_cmodel(int color_model)
286 int result = FileMPEG::zmpeg3_cmdl(color_model);
288 printf("DeviceMPEGInput::get_dev_cmodel: unknown color_model for libzmpeg3\n");
292 int DeviceMPEGInput::colormodel()
294 return color_model>=0 ? color_model : BC_YUV420P;
297 int DeviceMPEGInput::read_buffer(VFrame *frame)
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;
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();
321 switch( dev_cmodel ) {
322 case zmpeg3_t::cmdl_YUV420P: uvs = 2; break;
323 case zmpeg3_t::cmdl_YUV422P: uvs = 1; break;
326 int uvw = !uvs ? 0 : bpl / 2;
327 int uvh = !uvs ? 0 : 2*h / uvs;
328 uint8_t *rows[h + uvh], *rp = data;
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],
337 w,h, dev_cmodel, video_stream);
338 video_lock->unlock();
341 set_channel(channel);
346 int DeviceMPEGInput::read_audio(char *data, int size)
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);
362 int frame = (sample_bits * channels) / 8;
363 if( size > 0 && frame > 0 && audio_stream >= 0 &&
364 !src_stream(audio_lock) ) {
366 short *sdata = (short*)data;
367 int samples = size / frame;
369 int chans = channels;
370 for( int ch=0; ch<chans; ++ch ) {
372 src->read_audio(&bfr[0], ch, samples, audio_stream) :
373 src->reread_audio(&bfr[0], ch, samples, audio_stream);
376 for( int i=0; i<samples; ++i,k+=chans )
381 for( int i=0; i<samples; ++i,k+=chans )
386 audio_lock->unlock();
391 int DeviceMPEGInput::set_channel(Channel *channel)
393 //printf("DeviceMPEGInput::set_channel: enter %s\n",!channel ? "close" :
394 // channel == this->channel ? "reset" : channel->title);
395 decoder_lock->lock();
398 Channel *new_channel = 0;
400 new_channel = new Channel;
401 new_channel->copy_settings(channel);
402 new_channel->copy_usage(channel);
404 delete this->channel;
405 this->channel = new_channel;
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;
416 void DeviceMPEGInput::set_captioning(int strk)
418 mLock holds(decoder_lock);
420 if( src && video_stream >= 0 )
421 src->show_subtitle(video_stream, strk);
424 int DeviceMPEGInput::drop_frames(int frames)
426 mLock holds(decoder_lock);
428 if( src && video_stream >= 0 )
429 result = src->drop_frames(frames,video_stream);
433 double DeviceMPEGInput::audio_timestamp()
435 mLock holds(decoder_lock);
437 if( src && audio_stream >= 0 )
438 result = src->get_audio_time(audio_stream);
442 double DeviceMPEGInput::video_timestamp()
444 mLock holds(decoder_lock);
446 if( src && video_stream >= 0 )
447 ret = src->get_video_time(video_stream);
451 int DeviceMPEGInput::start_toc(const char *path, const char *toc_path)
453 if( !src || toc ) return -1;
454 toc = src->start_toc(path, toc_path);
456 toc_builder->start();
460 int DeviceMPEGInput::tick_toc()
462 if( record_fd < 0 || !src || !toc ) return 1;
463 while( toc_pos < src->record_position() )
464 toc->do_toc(&toc_pos);
468 int DeviceMPEGInput::start_record(int fd, int bsz)
471 return src ? src->start_record(fd, bsz) : -1;
474 int DeviceMPEGInput::stop_record()
476 int ret = src ? src->stop_record() : -1;
478 toc_builder->stop(1);
486 int DeviceMPEGInput::subchannel_count()
489 return src ? src->dvb.channel_count() : 0;
495 int DeviceMPEGInput::subchannel_definition(int subchan, char *name,
496 int &major, int &minor, int &total_astreams, int &total_vstreams)
499 int result = src != 0 ? 0 : -1;
500 if( !result ) result = src->dvb.get_channel(subchan, major, minor);
501 if( !result ) result = src->dvb.get_station_id(subchan, &name[0]);
502 if( !result ) result = src->dvb.total_astreams(subchan, total_astreams);
503 if( !result ) result = src->dvb.total_vstreams(subchan, total_vstreams);
510 int DeviceMPEGInput::subchannel_video_stream(int subchan, int vstream)
513 int result = src != 0 ? 0 : -1;
514 if( !result && src->dvb.vstream_number(subchan, vstream, result) )
522 int DeviceMPEGInput::subchannel_audio_stream(int subchan, int astream, char *enc)
525 int result = src != 0 ? 0 : -1;
526 if( src && src->dvb.astream_number(subchan, astream, result, enc) ) {
527 enc[0] = 0; result = -1;
535 int DeviceMPEGInput::get_video_pid(int track)
537 return !src ? -1 : src->video_pid(track);
540 int DeviceMPEGInput::get_video_info(int track, int &pid, double &framerate,
541 int &width, int &height, char *title)
543 //mLock holds(decoder_lock); caller of callback holds lock
545 pid = src->video_pid(track);
546 framerate = src->frame_rate(track);
547 width = src->video_width(track);
548 height = src->video_height(track);
549 if( !title ) return 0;
551 int elements = src->dvb.channel_count();
552 for( int n=0; n<elements; ++n ) {
553 int major, minor, total_vstreams, vstream, vidx;
554 if( src->dvb.get_channel(n, major, minor) ) continue;
555 if( src->dvb.total_vstreams(n,total_vstreams) ) continue;
556 for( vidx=0; vidx<total_vstreams; ++vidx ) {
557 if( src->dvb.vstream_number(n,vidx,vstream) ) continue;
558 if( vstream < 0 ) continue;
559 if( vstream == track ) {
560 sprintf(title, "%3d.%-3d", major, minor);
568 int DeviceMPEGInput::get_thumbnail(int stream, int64_t &position,
569 unsigned char *&thumbnail, int &ww, int &hh)
572 return src->get_thumbnail(stream, position, thumbnail, ww, hh);
575 int DeviceMPEGInput::set_skimming(int track, int skim, skim_fn fn, void *vp)
578 return !fn ? src->set_thumbnail_callback(track, 0, 0, 0, 0) :
579 src->set_thumbnail_callback(track, skim, 1, fn, vp);
583 Channel *DeviceMPEGInput::add_channel( ArrayList<Channel*> *channeldb, char *name,
584 int element, int major, int minor, int vstream, int astream, char *enc)
586 Channel *ch = new Channel;
587 ch->copy_settings(channel);
588 sprintf(ch->title,"%d.%d %s", major, minor, &name[0]);
589 sprintf(ch->device_name,"%d", get_channel());
590 if( astream >= 0 && enc && enc[0] ) {
591 char *cp = ch->title; cp += strlen(cp);
592 sprintf(cp," (%s)",&enc[0]);
594 ch->element = element;
595 ch->video_stream = vstream;
596 ch->audio_stream = astream;
597 channeldb->append(ch);
601 //printf(" channel %s\n",channel->title);
602 int DeviceMPEGInput::get_channeldb(ArrayList<Channel*> *channeldb)
604 //printf(" get channel record\n");
605 int count = subchannel_count();
606 for( int subchan=0; subchan<count; ++subchan ) {
607 char name[16], enc[8];
608 int vstream = -1, video_stream = -1;
609 int astream = -1, audio_stream = -1;
610 int major, minor, total_astreams, total_vstreams;
611 if( subchannel_definition(subchan,&name[0],
612 major, minor, total_astreams, total_vstreams)) continue;
613 if( total_astreams > 1 && total_vstreams > 1 )
614 printf(_("DeviceMPEGInput::get_channeldb::element %d"
615 " (id %d.%d) has %d/%d video/audio streams\n"),
616 subchan, major, minor, total_vstreams, total_astreams);
617 if( total_vstreams > 1 && total_astreams > 0 && (audio_stream =
618 subchannel_audio_stream(subchan, astream=0, enc)) >= 0 ) {
619 if( total_astreams > 1 )
620 printf(_(" only first audio stream will be used\n"));
621 for( int vstream=0; vstream<total_vstreams; ++vstream ) {
622 int video_stream = subchannel_video_stream(subchan, vstream);
623 if( video_stream < 0 ) continue;
624 Channel *ch = add_channel(channeldb, name, subchan,
625 major, minor, video_stream, audio_stream, enc);
626 char *cp = ch->title; cp += strlen(cp);
627 sprintf(cp," v%d",vstream+1);
631 if( total_astreams > 1 && total_vstreams > 0 && (video_stream =
632 subchannel_video_stream(subchan, vstream=0)) >= 0 ) {
633 if( total_vstreams > 1 )
634 printf(_(" only first video stream will be used\n"));
635 for( int astream=0; astream<total_astreams; ++astream ) {
636 int audio_stream = subchannel_audio_stream(subchan, astream, enc);
637 if( audio_stream < 0 ) continue;
638 Channel *ch = add_channel(channeldb, name, subchan,
639 major, minor, video_stream, audio_stream, enc);
640 char *cp = ch->title; cp += strlen(cp);
641 sprintf(cp," a%d",astream+1);
645 if( total_astreams > 0 || total_vstreams > 0 ) {
646 astream = vstream = -1;
647 video_stream = !total_vstreams ? -1 :
648 subchannel_video_stream(subchan, vstream = 0);
649 audio_stream = !total_astreams ? -1 :
650 subchannel_audio_stream(subchan, astream = 0, enc);
651 add_channel(channeldb, name, subchan,
652 major, minor, video_stream, audio_stream, enc);
658 int DeviceMPEGInput::create_channeldb(ArrayList<Channel*> *channeldb)
661 if( !src_stream() ) {
662 ret = get_channeldb(channeldb);
668 DeviceMPEG_TOC_Builder::
669 DeviceMPEG_TOC_Builder(DeviceMPEGInput *mpeg_dev)
672 this->mpeg_dev = mpeg_dev;
676 DeviceMPEG_TOC_Builder::
677 ~DeviceMPEG_TOC_Builder()
683 void DeviceMPEG_TOC_Builder::
688 if( !wait ) Thread::cancel();
693 void DeviceMPEG_TOC_Builder::
700 void DeviceMPEG_TOC_Builder::
703 Thread::enable_cancel();
706 Thread::disable_cancel();
707 mpeg_dev->tick_toc();
708 Thread::enable_cancel();
712 Thread::disable_cancel();
713 mpeg_dev->tick_toc();