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 "../hvirtual_config.h"
27 #include "audiompeg.h"
29 #include "chantables.h"
30 #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 #include <linux/videodev2.h>
54 Condition DeviceMPEGInput::in_mpeg_lock(1,"DeviceMPEGInput::in_mpeg_lock");
55 DeviceMPEGList DeviceMPEGInput::in_mpeg;
57 DeviceMPEGInput::DeviceMPEGInput(const char *name, int no)
58 : Garbage("DeviceMPEGInput")
60 //printf("new DeviceMPEGInput\n");
62 dev_name = strdup(name);
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);
70 DeviceMPEGInput::~DeviceMPEGInput()
72 //printf("delete DeviceMPEGInput\n");
80 if( dev_name ) free((void*)dev_name);
84 void DeviceMPEGInput::reset()
107 audio_stream = video_stream = -1;
110 channels = sample_bits = samplerate = 0;
111 total_vstreams = total_achannels = 0;
114 DeviceMPEGInput* DeviceMPEGInput::get_mpeg_device(
115 DeviceMPEGInput* (*new_device)(const char *name, int no),
116 const char *name, int no)
118 DeviceMPEGInput *current = in_mpeg.first;
120 if( current->device_number != no ) continue;
121 if( !strcmp(current->dev_name, name) ) break;
126 current = new_device(name, no);
127 in_mpeg.append(current);
135 DeviceMPEGInput* DeviceMPEGInput::get_mpeg_video(VideoDevice *video_device,
136 DeviceMPEGInput* (*new_device)(const char *name, int no),
137 const char *name, int no)
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;
146 in_mpeg_lock.unlock();
150 DeviceMPEGInput* DeviceMPEGInput::get_mpeg_audio(AudioDevice *audio_device,
151 DeviceMPEGInput* (*new_device)(const char *name, int no),
152 const char *name, int no)
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;
161 in_mpeg_lock.unlock();
165 void DeviceMPEGInput::put_mpeg_video()
167 //printf("put_mpeg_video\n");
168 in_mpeg_lock.lock("DeviceMPEGInput::put_mpeg_video");
171 in_mpeg_lock.unlock();
174 void DeviceMPEGInput::put_mpeg_audio()
176 //printf("put_mpeg_audio\n");
177 in_mpeg_lock.lock("DeviceMPEGInput::put_mpeg_audio");
180 in_mpeg_lock.unlock();
184 MWindow *DeviceMPEGInput::get_mwindow()
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();
193 int DeviceMPEGInput::get_stream(int reopen)
197 //printf("DeviceMPEGInput::get_stream delete src %p\n",src);
199 audio_stream = video_stream = -1;
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;
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);
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;
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();
240 int total_astreams = src->total_astreams();
241 for( int stream=0; stream<total_astreams; ++stream )
242 total_achannels += src->audio_channels(stream);
245 fprintf(stderr,"DeviceMPEGInput::get_stream open failed (%d)\n", ret);
249 if( ret ) close_dev();
253 int DeviceMPEGInput::src_stream(Mutex *stream)
256 decoder_lock->lock();
261 video_lock->unlock();
262 audio_lock->unlock();
264 if( !ret && stream ) stream->lock();
265 if( ret || stream ) decoder_lock->unlock();
270 DeviceMPEGInput::src_lock()
272 decoder_lock->lock();
273 if( src ) return src;
274 decoder_lock->unlock();
278 void DeviceMPEGInput::src_unlock()
280 decoder_lock->unlock();
283 int DeviceMPEGInput::get_dev_cmodel(int color_model)
285 int result = FileMPEG::zmpeg3_cmdl(color_model);
287 printf("DeviceMPEGInput::get_dev_cmodel: unknown color_model for libzmpeg3\n");
291 int DeviceMPEGInput::colormodel()
293 return color_model>=0 ? color_model : BC_YUV420P;
296 int DeviceMPEGInput::read_buffer(VFrame *frame)
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;
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();
320 switch( dev_cmodel ) {
321 case zmpeg3_t::cmdl_YUV420P: uvs = 2; break;
322 case zmpeg3_t::cmdl_YUV422P: uvs = 1; break;
325 int uvw = !uvs ? 0 : bpl / 2;
326 int uvh = !uvs ? 0 : 2*h / uvs;
327 uint8_t *rows[h + uvh], *rp = data;
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],
336 w,h, dev_cmodel, video_stream);
337 video_lock->unlock();
340 set_channel(channel);
345 int DeviceMPEGInput::read_audio(char *data, int size)
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);
361 int frame = (sample_bits * channels) / 8;
362 if( size > 0 && frame > 0 && audio_stream >= 0 &&
363 !src_stream(audio_lock) ) {
365 short *sdata = (short*)data;
366 int samples = size / frame;
368 int chans = channels;
369 for( int ch=0; ch<chans; ++ch ) {
371 src->read_audio(&bfr[0], ch, samples, audio_stream) :
372 src->reread_audio(&bfr[0], ch, samples, audio_stream);
375 for( int i=0; i<samples; ++i,k+=chans )
380 for( int i=0; i<samples; ++i,k+=chans )
385 audio_lock->unlock();
390 int DeviceMPEGInput::set_channel(Channel *channel)
392 //printf("DeviceMPEGInput::set_channel: enter %s\n",!channel ? "close" :
393 // channel == this->channel ? "reset" : channel->title);
394 decoder_lock->lock();
397 Channel *new_channel = 0;
399 new_channel = new Channel;
400 new_channel->copy_settings(channel);
401 new_channel->copy_usage(channel);
403 delete this->channel;
404 this->channel = new_channel;
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;
415 void DeviceMPEGInput::set_captioning(int strk)
417 mLock holds(decoder_lock);
419 if( src && video_stream >= 0 )
420 src->show_subtitle(video_stream, strk);
423 int DeviceMPEGInput::drop_frames(int frames)
425 mLock holds(decoder_lock);
427 if( src && video_stream >= 0 )
428 result = src->drop_frames(frames,video_stream);
432 double DeviceMPEGInput::audio_timestamp()
434 mLock holds(decoder_lock);
436 if( src && audio_stream >= 0 )
437 result = src->get_audio_time(audio_stream);
441 double DeviceMPEGInput::video_timestamp()
443 mLock holds(decoder_lock);
445 if( src && video_stream >= 0 )
446 ret = src->get_video_time(video_stream);
450 int DeviceMPEGInput::start_toc(const char *path, const char *toc_path)
452 if( !src || toc ) return -1;
453 toc = src->start_toc(path, toc_path);
455 toc_builder->start();
459 int DeviceMPEGInput::tick_toc()
461 if( record_fd < 0 || !src || !toc ) return 1;
462 while( toc_pos < src->record_position() )
463 toc->do_toc(&toc_pos);
467 int DeviceMPEGInput::start_record(int fd, int bsz)
470 return src ? src->start_record(fd, bsz) : -1;
473 int DeviceMPEGInput::stop_record()
475 int ret = src ? src->stop_record() : -1;
477 toc_builder->stop(1);
485 int DeviceMPEGInput::subchannel_count()
487 return src ? src->dvb.channel_count() : 0;
490 int DeviceMPEGInput::subchannel_definition(int subchan, char *name,
491 int &major, int &minor, int &total_astreams, int &total_vstreams)
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);
501 int DeviceMPEGInput::subchannel_video_stream(int subchan, int vstream)
503 int result = src != 0 ? 0 : -1;
504 if( !result && src->dvb.vstream_number(subchan, vstream, result) )
509 int DeviceMPEGInput::subchannel_audio_stream(int subchan, int astream, char *enc)
511 int result = src != 0 ? 0 : -1;
512 if( src && src->dvb.astream_number(subchan, astream, result, enc) ) {
513 enc[0] = 0; result = -1;
518 int DeviceMPEGInput::get_video_pid(int track)
520 return !src ? -1 : src->video_pid(track);
523 int DeviceMPEGInput::get_video_info(int track, int &pid, double &framerate,
524 int &width, int &height, char *title)
526 //mLock holds(decoder_lock); caller of callback holds lock
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;
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);
551 int DeviceMPEGInput::get_thumbnail(int stream, int64_t &position,
552 unsigned char *&thumbnail, int &ww, int &hh)
555 return src->get_thumbnail(stream, position, thumbnail, ww, hh);
558 int DeviceMPEGInput::set_skimming(int track, int skim, skim_fn fn, void *vp)
561 return !fn ? src->set_thumbnail_callback(track, 0, 0, 0, 0) :
562 src->set_thumbnail_callback(track, skim, 1, fn, vp);
566 Channel *DeviceMPEGInput::add_channel( ArrayList<Channel*> *channeldb, char *name,
567 int element, int major, int minor, int vstream, int astream, char *enc)
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]);
577 ch->element = element;
578 ch->video_stream = vstream;
579 ch->audio_stream = astream;
580 channeldb->append(ch);
584 //printf(" channel %s\n",channel->title);
585 int DeviceMPEGInput::get_channeldb(ArrayList<Channel*> *channeldb)
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);
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);
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);
641 int DeviceMPEGInput::create_channeldb(ArrayList<Channel*> *channeldb)
644 if( !src_stream() ) {
645 ret = get_channeldb(channeldb);
651 DeviceMPEG_TOC_Builder::
652 DeviceMPEG_TOC_Builder(DeviceMPEGInput *mpeg_dev)
655 this->mpeg_dev = mpeg_dev;
659 DeviceMPEG_TOC_Builder::
660 ~DeviceMPEG_TOC_Builder()
666 void DeviceMPEG_TOC_Builder::
671 if( !wait ) Thread::cancel();
676 void DeviceMPEG_TOC_Builder::
683 void DeviceMPEG_TOC_Builder::
686 Thread::enable_cancel();
689 Thread::disable_cancel();
690 mpeg_dev->tick_toc();
691 Thread::enable_cancel();
695 Thread::disable_cancel();
696 mpeg_dev->tick_toc();