From db8ca09b9703670bfd4ef7d0f5b1c3aa8bb3b844 Mon Sep 17 00:00:00 2001 From: Stefan Seyfried Date: Mon, 8 Oct 2012 20:34:38 +0200 Subject: [PATCH] add implementation for boxtype "generic" This is mostly a dummy implementation except for the dmx class which should be working. It is intended for testing on PCs with budget DVB cards which don't have a decoder anyway. Origin commit data ------------------ Branch: master Commit: https://github.com/neutrino-images/ni-libstb-hal/commit/9f433f9dfadd1b237b7ce8853e5eb36f6b2f823b Author: Stefan Seyfried Date: 2012-10-08 (Mon, 08 Oct 2012) ------------------ This commit was generated by Migit --- .gitignore | 1 + Makefile.am | 12 + acinclude.m4 | 2 +- configure.ac | 1 + generic-pc/Makefile.am | 19 ++ generic-pc/audio.cpp | 142 +++++++++++ generic-pc/audio_lib.h | 98 ++++++++ generic-pc/cs_api.h | 1 + generic-pc/dmx.cpp | 480 +++++++++++++++++++++++++++++++++++++ generic-pc/dmx_cs.h | 1 + generic-pc/dmx_lib.h | 67 ++++++ generic-pc/hardware_caps.c | 37 +++ generic-pc/init.cpp | 21 ++ generic-pc/init_lib.h | 5 + generic-pc/playback.cpp | 74 ++++++ generic-pc/playback.h | 34 +++ generic-pc/pwrmngr.cpp | 1 + generic-pc/pwrmngr.h | 1 + generic-pc/record.cpp | 1 + generic-pc/record_lib.h | 1 + generic-pc/video.cpp | 150 ++++++++++++ generic-pc/video_lib.h | 168 +++++++++++++ include/audio_td.h | 2 + include/cs_api.h | 2 + include/dmx_td.h | 2 + include/playback_td.h | 2 + include/pwrmngr.h | 2 + include/record_td.h | 2 + include/video_td.h | 2 + 29 files changed, 1330 insertions(+), 1 deletion(-) create mode 100644 generic-pc/Makefile.am create mode 100644 generic-pc/audio.cpp create mode 100644 generic-pc/audio_lib.h create mode 120000 generic-pc/cs_api.h create mode 100644 generic-pc/dmx.cpp create mode 100644 generic-pc/dmx_cs.h create mode 100644 generic-pc/dmx_lib.h create mode 100644 generic-pc/hardware_caps.c create mode 100644 generic-pc/init.cpp create mode 100644 generic-pc/init_lib.h create mode 100644 generic-pc/playback.cpp create mode 100644 generic-pc/playback.h create mode 120000 generic-pc/pwrmngr.cpp create mode 120000 generic-pc/pwrmngr.h create mode 120000 generic-pc/record.cpp create mode 120000 generic-pc/record_lib.h create mode 100644 generic-pc/video.cpp create mode 100644 generic-pc/video_lib.h diff --git a/.gitignore b/.gitignore index 6a82b96..fab9b32 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ /libspark/Makefile.in /libtriple/Makefile.in /azbox/Makefile.in +/generic-pc/Makefile.in /ltmain.sh /missing /Makefile.in diff --git a/Makefile.am b/Makefile.am index a016297..c3e03eb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -44,6 +44,18 @@ libstb_hal_a_LIBADD += \ azbox/record.o \ azbox/video.o endif +if BOXTYPE_GENERIC +SUBDIRS += generic-pc +libstb_hal_a_LIBADD += \ + generic-pc/audio.o \ + generic-pc/dmx.o \ + generic-pc/hardware_caps.o \ + generic-pc/init.o \ + generic-pc/playback.o \ + generic-pc/pwrmngr.o \ + generic-pc/record.o \ + generic-pc/video.o +endif if BOXTYPE_SPARK SUBDIRS += libspark libeplayer3 libstb_hal_a_LIBADD += \ diff --git a/acinclude.m4 b/acinclude.m4 index a144251..0259d90 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -277,7 +277,7 @@ AC_ARG_WITH(boxtype, ;; *) AC_MSG_ERROR([bad value $withval for --with-boxtype]) ;; - esac], [BOXTYPE="coolstream"]) + esac], [BOXTYPE="generic"]) AC_ARG_WITH(boxmodel, [ --with-boxmodel valid for dreambox: dm500, dm500plus, dm600pvr, dm56x0, dm7000, dm7020, dm7025 diff --git a/configure.ac b/configure.ac index d23674a..5082cb3 100644 --- a/configure.ac +++ b/configure.ac @@ -23,6 +23,7 @@ Makefile common/Makefile libeplayer3/Makefile azbox/Makefile +generic-pc/Makefile libtriple/Makefile libspark/Makefile tools/Makefile diff --git a/generic-pc/Makefile.am b/generic-pc/Makefile.am new file mode 100644 index 0000000..f234200 --- /dev/null +++ b/generic-pc/Makefile.am @@ -0,0 +1,19 @@ +INCLUDES = \ + -I$(top_srcdir)/common + +# this library is not used for linking, so call it libdummy... +noinst_LIBRARIES = libdummy.a + +AM_CXXFLAGS = -fno-rtti -fno-exceptions -fno-strict-aliasing +AM_LDFLAGS = -lpthread + +libdummy_a_SOURCES = \ + hardware_caps.c \ + dmx.cpp \ + video.cpp \ + audio.cpp \ + init.cpp \ + playback.cpp \ + pwrmngr.cpp \ + record.cpp + diff --git a/generic-pc/audio.cpp b/generic-pc/audio.cpp new file mode 100644 index 0000000..98494e3 --- /dev/null +++ b/generic-pc/audio.cpp @@ -0,0 +1,142 @@ +/* dummy cAudio implementation that does nothing for now */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "audio_lib.h" +#include "lt_debug.h" + +#define AUDIO_DEVICE "/dev/dvb/adapter0/audio0" +#define lt_debug(args...) _lt_debug(TRIPLE_DEBUG_AUDIO, this, args) +#define lt_info(args...) _lt_info(TRIPLE_DEBUG_AUDIO, this, args) + +#include + +cAudio * audioDecoder = NULL; + +cAudio::cAudio(void *, void *, void *) +{ +} + +cAudio::~cAudio(void) +{ + closeDevice(); +} + +void cAudio::openDevice(void) +{ + lt_debug("%s\n", __func__); +} + +void cAudio::closeDevice(void) +{ + lt_debug("%s\n", __func__); +} + +int cAudio::do_mute(bool enable, bool remember) +{ + lt_debug("%s(%d, %d)\n", __func__, enable, remember); + return 0; +} + +int cAudio::setVolume(unsigned int left, unsigned int right) +{ + lt_debug("%s(%d, %d)\n", __func__, left, right); + return 0; +} + +int cAudio::Start(void) +{ + lt_debug("%s\n", __func__); + return 0; +} + +int cAudio::Stop(void) +{ + lt_debug("%s\n", __func__); + return 0; +} + +bool cAudio::Pause(bool /*Pcm*/) +{ + return true; +}; + +void cAudio::SetSyncMode(AVSYNC_TYPE Mode) +{ + lt_debug("%s %d\n", __func__, Mode); +}; + +void cAudio::SetStreamType(AUDIO_FORMAT type) +{ + lt_debug("%s %d\n", __func__, type); +}; + +int cAudio::setChannel(int channel) +{ + return 0; +}; + +int cAudio::PrepareClipPlay(int ch, int srate, int bits, int little_endian) +{ + lt_debug("%s ch %d srate %d bits %d le %d\n", __func__, ch, srate, bits, little_endian); + return 0; +}; + +int cAudio::WriteClip(unsigned char * /*buffer*/, int /*size*/) +{ + lt_debug("cAudio::%s\n", __func__); + return 0; +}; + +int cAudio::StopClip() +{ + lt_debug("%s\n", __func__); + return 0; +}; + +void cAudio::getAudioInfo(int &type, int &layer, int &freq, int &bitrate, int &mode) +{ + lt_debug("%s\n", __func__); + type = 0; + layer = 0; + freq = 0; + bitrate = 0; + mode = 0; +}; + +void cAudio::SetSRS(int /*iq_enable*/, int /*nmgr_enable*/, int /*iq_mode*/, int /*iq_level*/) +{ + lt_debug("%s\n", __func__); +}; + +void cAudio::SetHdmiDD(bool enable) +{ + lt_debug("%s %d\n", __func__, enable); +}; + +void cAudio::SetSpdifDD(bool enable) +{ + lt_debug("%s %d\n", __func__, enable); +}; + +void cAudio::ScheduleMute(bool On) +{ + lt_debug("%s %d\n", __func__, On); +}; + +void cAudio::EnableAnalogOut(bool enable) +{ + lt_debug("%s %d\n", __func__, enable); +}; + +void cAudio::setBypassMode(bool disable) +{ + lt_debug("%s %d\n", __func__, disable); +} diff --git a/generic-pc/audio_lib.h b/generic-pc/audio_lib.h new file mode 100644 index 0000000..871060d --- /dev/null +++ b/generic-pc/audio_lib.h @@ -0,0 +1,98 @@ +/* public header file */ + +#ifndef _AUDIO_LIB_H_ +#define _AUDIO_LIB_H_ + +#include "../common/cs_types.h" + +typedef enum +{ + AUDIO_SYNC_WITH_PTS, + AUDIO_NO_SYNC, + AUDIO_SYNC_AUDIO_MASTER +} AUDIO_SYNC_MODE; + +typedef enum { + HDMI_ENCODED_OFF, + HDMI_ENCODED_AUTO, + HDMI_ENCODED_FORCED +} HDMI_ENCODED_MODE; + +typedef enum +{ + AUDIO_FMT_AUTO = 0, + AUDIO_FMT_MPEG, + AUDIO_FMT_MP3, + AUDIO_FMT_DOLBY_DIGITAL, + AUDIO_FMT_BASIC = AUDIO_FMT_DOLBY_DIGITAL, + AUDIO_FMT_AAC, + AUDIO_FMT_AAC_PLUS, + AUDIO_FMT_DD_PLUS, + AUDIO_FMT_DTS, + AUDIO_FMT_AVS, + AUDIO_FMT_MLP, + AUDIO_FMT_WMA, + AUDIO_FMT_MPG1, // TD only. For Movieplayer / cPlayback + AUDIO_FMT_ADVANCED = AUDIO_FMT_MLP +} AUDIO_FORMAT; + +class cAudio +{ + friend class cPlayback; + private: + int fd; + bool Muted; + + int clipfd; /* for pcm playback */ + int mixer_fd; /* if we are using the OSS mixer */ + int mixer_num; /* oss mixer to use, if any */ + + AUDIO_FORMAT StreamType; + AUDIO_SYNC_MODE SyncMode; + bool started; + + int volume; + + void openDevice(void); + void closeDevice(void); + + int do_mute(bool enable, bool remember); + void setBypassMode(bool disable); + public: + /* construct & destruct */ + cAudio(void *, void *, void *); + ~cAudio(void); + + void *GetHandle() { return NULL; }; + /* shut up */ + int mute(bool remember = true) { return do_mute(true, remember); }; + int unmute(bool remember = true) { return do_mute(false, remember); }; + + /* volume, min = 0, max = 255 */ + int setVolume(unsigned int left, unsigned int right); + int getVolume(void) { return volume;} + bool getMuteStatus(void) { return Muted; }; + + /* start and stop audio */ + int Start(void); + int Stop(void); + bool Pause(bool Pcm = true); + void SetStreamType(AUDIO_FORMAT type); + void SetSyncMode(AVSYNC_TYPE Mode); + + /* select channels */ + int setChannel(int channel); + int PrepareClipPlay(int uNoOfChannels, int uSampleRate, int uBitsPerSample, int bLittleEndian); + int WriteClip(unsigned char * buffer, int size); + int StopClip(); + void getAudioInfo(int &type, int &layer, int& freq, int &bitrate, int &mode); + void SetSRS(int iq_enable, int nmgr_enable, int iq_mode, int iq_level); + bool IsHdmiDDSupported(); + void SetHdmiDD(bool enable); + void SetSpdifDD(bool enable); + void ScheduleMute(bool On); + void EnableAnalogOut(bool enable); +}; + +#endif + diff --git a/generic-pc/cs_api.h b/generic-pc/cs_api.h new file mode 120000 index 0000000..a794ffd --- /dev/null +++ b/generic-pc/cs_api.h @@ -0,0 +1 @@ +../libspark/cs_api.h \ No newline at end of file diff --git a/generic-pc/dmx.cpp b/generic-pc/dmx.cpp new file mode 100644 index 0000000..7a61a90 --- /dev/null +++ b/generic-pc/dmx.cpp @@ -0,0 +1,480 @@ +#include "config.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "dmx_lib.h" +#include "lt_debug.h" + +#define lt_debug(args...) _lt_debug(TRIPLE_DEBUG_DEMUX, this, args) +#define lt_info(args...) _lt_info(TRIPLE_DEBUG_DEMUX, this, args) +#define lt_info_c(args...) _lt_info(TRIPLE_DEBUG_DEMUX, NULL, args) + +#define dmx_err(_errfmt, _errstr, _revents) do { \ + uint16_t _pid = (uint16_t)-1; uint16_t _f = 0;\ + if (dmx_type == DMX_PES_CHANNEL) { \ + _pid = p_flt.pid; \ + } else if (dmx_type == DMX_PSI_CHANNEL) { \ + _pid = s_flt.pid; _f = s_flt.filter.filter[0]; \ + }; \ + lt_info("%s " _errfmt " fd:%d, ev:0x%x %s pid:0x%04hx flt:0x%02hx\n", \ + __func__, _errstr, fd, _revents, DMX_T[dmx_type], _pid, _f); \ +} while(0); + +cDemux *videoDemux = NULL; +cDemux *audioDemux = NULL; +//cDemux *pcrDemux = NULL; + +static const char *DMX_T[] = { + "DMX_INVALID", + "DMX_VIDEO", + "DMX_AUDIO", + "DMX_PES", + "DMX_PSI", + "DMX_PIP", + "DMX_TP", + "DMX_PCR" +}; + +/* map the device numbers. for now only demux0 is used */ +static const char *devname[] = { + "/dev/dvb/adapter0/demux0", + "/dev/dvb/adapter0/demux0", + "/dev/dvb/adapter0/demux0" +}; + +/* uuuugly */ +static int dmx_tp_count = 0; +#define MAX_TS_COUNT 8 + +cDemux::cDemux(int n) +{ + if (n < 0 || n > 2) + { + lt_info("%s ERROR: n invalid (%d)\n", __FUNCTION__, n); + num = 0; + } + else + num = n; + fd = -1; + measure = false; + last_measure = 0; + last_data = 0; +} + +cDemux::~cDemux() +{ + lt_debug("%s #%d fd: %d\n", __FUNCTION__, num, fd); + Close(); +} + +bool cDemux::Open(DMX_CHANNEL_TYPE pes_type, void * /*hVideoBuffer*/, int uBufferSize) +{ + int devnum = num; + int flags = O_RDWR|O_CLOEXEC; + if (fd > -1) + lt_info("%s FD ALREADY OPENED? fd = %d\n", __FUNCTION__, fd); + + if (pes_type != DMX_PSI_CHANNEL) + flags |= O_NONBLOCK; + + fd = open(devname[devnum], flags); + if (fd < 0) + { + lt_info("%s %s: %m\n", __FUNCTION__, devname[devnum]); + return false; + } + lt_debug("%s #%d pes_type: %s(%d), uBufferSize: %d fd: %d\n", __func__, + num, DMX_T[pes_type], pes_type, uBufferSize, fd); + + dmx_type = pes_type; +#if 0 + if (!pesfds.empty()) + { + lt_info("%s ERROR! pesfds not empty!\n", __FUNCTION__); /* TODO: error handling */ + return false; + } + int n = DMX_SOURCE_FRONT0; + if (ioctl(fd, DMX_SET_SOURCE, &n) < 0) + lt_info("%s DMX_SET_SOURCE %d failed! (%m)\n", __func__, n); +#endif + if (uBufferSize > 0) + { + /* probably uBufferSize == 0 means "use default size". TODO: find a reasonable default */ + if (ioctl(fd, DMX_SET_BUFFER_SIZE, uBufferSize) < 0) + lt_info("%s DMX_SET_BUFFER_SIZE failed (%m)\n", __func__); + } + buffersize = uBufferSize; + + return true; +} + +void cDemux::Close(void) +{ + lt_debug("%s #%d, fd = %d\n", __FUNCTION__, num, fd); + if (fd < 0) + { + lt_info("%s #%d: not open!\n", __FUNCTION__, num); + return; + } + + for (std::vector::const_iterator i = pesfds.begin(); i != pesfds.end(); ++i) + { + lt_debug("%s stopping and closing demux fd %d pid 0x%04x\n", __FUNCTION__, (*i).fd, (*i).pid); + if (ioctl((*i).fd, DMX_STOP) < 0) + perror("DEMUX_STOP"); + if (close((*i).fd) < 0) + perror("close"); + } + pesfds.clear(); + ioctl(fd, DMX_STOP); + close(fd); + fd = -1; + if (measure) + return; + if (dmx_type == DMX_TP_CHANNEL) + { + dmx_tp_count--; + if (dmx_tp_count < 0) + { + lt_info("%s dmx_tp_count < 0!!\n", __func__); + dmx_tp_count = 0; + } + } +} + +bool cDemux::Start(bool) +{ + lt_debug("%s #%d fd: %d type: %s\n", __func__, num, fd, DMX_T[dmx_type]); + if (fd < 0) + { + lt_info("%s #%d: not open!\n", __FUNCTION__, num); + return false; + } + + for (std::vector::const_iterator i = pesfds.begin(); i != pesfds.end(); ++i) + { + lt_debug("%s starting demux fd %d pid 0x%04x\n", __FUNCTION__, (*i).fd, (*i).pid); + if (ioctl((*i).fd, DMX_START) < 0) + perror("DMX_START"); + } + ioctl(fd, DMX_START); + return true; +} + +bool cDemux::Stop(void) +{ + lt_debug("%s #%d fd: %d type: %s\n", __func__, num, fd, DMX_T[dmx_type]); + if (fd < 0) + { + lt_info("%s #%d: not open!\n", __FUNCTION__, num); + return false; + } + for (std::vector::const_iterator i = pesfds.begin(); i != pesfds.end(); ++i) + { + lt_debug("%s stopping demux fd %d pid 0x%04x\n", __FUNCTION__, (*i).fd, (*i).pid); + if (ioctl((*i).fd, DMX_STOP) < 0) + perror("DMX_STOP"); + } + ioctl(fd, DMX_STOP); + return true; +} + +int cDemux::Read(unsigned char *buff, int len, int timeout) +{ +#if 0 + if (len != 4095 && timeout != 100) + fprintf(stderr, "cDemux::%s #%d fd: %d type: %s len: %d timeout: %d\n", + __FUNCTION__, num, fd, DMX_T[dmx_type], len, timeout); +#endif + int rc; + struct pollfd ufds; + ufds.fd = fd; + ufds.events = POLLIN|POLLPRI|POLLERR; + ufds.revents = 0; + + if (timeout > 0) + { + retry: + rc = ::poll(&ufds, 1, timeout); + if (!rc) + return 0; // timeout + else if (rc < 0) + { + dmx_err("poll: %s,", strerror(errno), 0) + //lt_info("%s poll: %m\n", __FUNCTION__); + /* happens, when running under gdb... */ + if (errno == EINTR) + goto retry; + return -1; + } +#if 0 + if (ufds.revents & POLLERR) /* POLLERR means buffer error, i.e. buffer overflow */ + { + dmx_err("received %s,", "POLLERR", ufds.revents); + /* this seems to happen sometimes at recording start, without bad effects */ + return 0; + } +#endif + if (ufds.revents & POLLHUP) /* we get POLLHUP if e.g. a too big DMX_BUFFER_SIZE was set */ + { + dmx_err("received %s,", "POLLHUP", ufds.revents); + return -1; + } + if (!(ufds.revents & POLLIN)) /* we requested POLLIN but did not get it? */ + { + dmx_err("received %s, please report!", "POLLIN", ufds.revents); + return 0; + } + } + + rc = ::read(fd, buff, len); + //fprintf(stderr, "fd %d ret: %d\n", fd, rc); + if (rc < 0) + dmx_err("read: %s", strerror(errno), 0); + + return rc; +} + +bool cDemux::sectionFilter(unsigned short pid, const unsigned char * const filter, + const unsigned char * const mask, int len, int timeout, + const unsigned char * const negmask) +{ + int length = len; + memset(&s_flt, 0, sizeof(s_flt)); + + if (len > DMX_FILTER_SIZE) + { + lt_info("%s #%d: len too long: %d, DMX_FILTER_SIZE %d\n", __func__, num, len, DMX_FILTER_SIZE); + length = DMX_FILTER_SIZE; + } + s_flt.pid = pid; + s_flt.timeout = timeout; + memcpy(s_flt.filter.filter, filter, len); + memcpy(s_flt.filter.mask, mask, len); + if (negmask != NULL) + memcpy(s_flt.filter.mode, negmask, len); + + s_flt.flags = DMX_IMMEDIATE_START|DMX_CHECK_CRC; + + int to = 0; + switch (filter[0]) { + case 0x00: /* program_association_section */ + to = 2000; + break; + case 0x01: /* conditional_access_section */ + to = 6000; + break; + case 0x02: /* program_map_section */ + to = 1500; + break; + case 0x03: /* transport_stream_description_section */ + to = 10000; + break; + /* 0x04 - 0x3F: reserved */ + case 0x40: /* network_information_section - actual_network */ + to = 10000; + break; + case 0x41: /* network_information_section - other_network */ + to = 15000; + break; + case 0x42: /* service_description_section - actual_transport_stream */ + to = 10000; + break; + /* 0x43 - 0x45: reserved for future use */ + case 0x46: /* service_description_section - other_transport_stream */ + to = 10000; + break; + /* 0x47 - 0x49: reserved for future use */ + case 0x4A: /* bouquet_association_section */ + to = 11000; + break; + /* 0x4B - 0x4D: reserved for future use */ + case 0x4E: /* event_information_section - actual_transport_stream, present/following */ + to = 2000; + break; + case 0x4F: /* event_information_section - other_transport_stream, present/following */ + to = 10000; + break; + /* 0x50 - 0x5F: event_information_section - actual_transport_stream, schedule */ + /* 0x60 - 0x6F: event_information_section - other_transport_stream, schedule */ + case 0x70: /* time_date_section */ + s_flt.flags &= ~DMX_CHECK_CRC; /* section has no CRC */ + //s_flt.pid = 0x0014; + to = 30000; + break; + case 0x71: /* running_status_section */ + s_flt.flags &= ~DMX_CHECK_CRC; /* section has no CRC */ + to = 0; + break; + case 0x72: /* stuffing_section */ + s_flt.flags &= ~DMX_CHECK_CRC; /* section has no CRC */ + to = 0; + break; + case 0x73: /* time_offset_section */ + //s_flt.pid = 0x0014; + to = 30000; + break; + /* 0x74 - 0x7D: reserved for future use */ + case 0x7E: /* discontinuity_information_section */ + s_flt.flags &= ~DMX_CHECK_CRC; /* section has no CRC */ + to = 0; + break; + case 0x7F: /* selection_information_section */ + to = 0; + break; + /* 0x80 - 0x8F: ca_message_section */ + /* 0x90 - 0xFE: user defined */ + /* 0xFF: reserved */ + default: + break; +// return -1; + } + /* the negmask == NULL is a hack: the users of negmask are PMT-update + * and sectionsd EIT-Version change. And they really want no timeout + * if timeout == 0 instead of "default timeout" */ + if (timeout == 0 && negmask == NULL) + s_flt.timeout = to; + + lt_debug("%s #%d pid:0x%04hx fd:%d type:%s len:%d to:%d flags:%x flt[0]:%02x\n", __func__, num, + pid, fd, DMX_T[dmx_type], len, s_flt.timeout,s_flt.flags, s_flt.filter.filter[0]); +#if 0 + fprintf(stderr,"filt: ");for(int i=0;i= 0x0002 && pid <= 0x000f) || pid >= 0x1fff) + return false; + + lt_debug("%s #%d pid: 0x%04hx fd: %d type: %s\n", __FUNCTION__, num, pid, fd, DMX_T[dmx_type]); + + memset(&p_flt, 0, sizeof(p_flt)); + p_flt.pid = pid; + p_flt.output = DMX_OUT_DECODER; + p_flt.input = DMX_IN_FRONTEND; + + switch (dmx_type) { + case DMX_PCR_ONLY_CHANNEL: + p_flt.pes_type = DMX_PES_PCR; + break; + case DMX_AUDIO_CHANNEL: + p_flt.pes_type = DMX_PES_AUDIO; + break; + case DMX_VIDEO_CHANNEL: + p_flt.pes_type = DMX_PES_VIDEO; + break; + case DMX_PES_CHANNEL: + p_flt.pes_type = DMX_PES_OTHER; + p_flt.output = DMX_OUT_TAP; + break; + case DMX_TP_CHANNEL: + p_flt.pes_type = DMX_PES_OTHER; + p_flt.output = DMX_OUT_TSDEMUX_TAP; + break; + default: + lt_info("%s #%d invalid dmx_type %d!\n", __func__, num, dmx_type); + return false; + } + return (ioctl(fd, DMX_SET_PES_FILTER, &p_flt) >= 0); +} + +void cDemux::SetSyncMode(AVSYNC_TYPE /*mode*/) +{ + lt_debug("%s #%d\n", __FUNCTION__, num); +} + +void *cDemux::getBuffer() +{ + lt_debug("%s #%d\n", __FUNCTION__, num); + return NULL; +} + +void *cDemux::getChannel() +{ + lt_debug("%s #%d\n", __FUNCTION__, num); + return NULL; +} + +bool cDemux::addPid(unsigned short Pid) +{ + lt_debug("%s: pid 0x%04hx\n", __func__, Pid); + pes_pids pfd; + int ret; + struct dmx_pes_filter_params p; + if (dmx_type != DMX_TP_CHANNEL) + { + lt_info("%s pes_type %s not implemented yet! pid=%hx\n", __FUNCTION__, DMX_T[dmx_type], Pid); + return false; + } + if (fd == -1) + lt_info("%s bucketfd not yet opened? pid=%hx\n", __FUNCTION__, Pid); + ret = (ioctl(fd, DMX_ADD_PID, &Pid)); + if (ret < 0) + lt_info("%s: DMX_ADD_PID (%m)\n", __func__); + return (ret != -1); +} + +void cDemux::removePid(unsigned short Pid) +{ + if (dmx_type != DMX_TP_CHANNEL) + { + lt_info("%s pes_type %s not implemented yet! pid=%hx\n", __FUNCTION__, DMX_T[dmx_type], Pid); + return; + } + for (std::vector::iterator i = pesfds.begin(); i != pesfds.end(); ++i) + { + if ((*i).pid == Pid) { + lt_debug("removePid: removing demux fd %d pid 0x%04x\n", (*i).fd, Pid); + if (ioctl((*i).fd, DMX_STOP) < 0) + perror("DMX_STOP"); + if (close((*i).fd) < 0) + perror("close"); + pesfds.erase(i); + return; /* TODO: what if the same PID is there multiple times */ + } + } + lt_info("%s pid 0x%04x not found\n", __FUNCTION__, Pid); +} + +void cDemux::getSTC(int64_t * STC) +{ + int64_t pts = 0; + *STC = pts; +} + +int cDemux::getUnit(void) +{ + lt_debug("%s #%d\n", __FUNCTION__, num); + /* just guessed that this is the right thing to do. + right now this is only used by the CA code which is stubbed out + anyway */ + return num; +} + +bool cDemux::SetSource(int unit, int source) +{ + lt_info_c("%s(%d, %d): not implemented yet\n", __func__, unit, source); + return true; +} diff --git a/generic-pc/dmx_cs.h b/generic-pc/dmx_cs.h new file mode 100644 index 0000000..175d8cb --- /dev/null +++ b/generic-pc/dmx_cs.h @@ -0,0 +1 @@ +#include "dmx_lib.h" diff --git a/generic-pc/dmx_lib.h b/generic-pc/dmx_lib.h new file mode 100644 index 0000000..ffd293e --- /dev/null +++ b/generic-pc/dmx_lib.h @@ -0,0 +1,67 @@ +#ifndef __DEMUX_TD_H +#define __DEMUX_TD_H + +#include +#include +#include +#include +#include +#include "../common/cs_types.h" + +typedef enum +{ + DMX_INVALID = 0, + DMX_VIDEO_CHANNEL = 1, + DMX_AUDIO_CHANNEL, + DMX_PES_CHANNEL, + DMX_PSI_CHANNEL, + DMX_PIP_CHANNEL, + DMX_TP_CHANNEL, + DMX_PCR_ONLY_CHANNEL +} DMX_CHANNEL_TYPE; + +typedef struct +{ + int fd; + unsigned short pid; +} pes_pids; + +class cDemux +{ + private: + int num; + int fd; + int buffersize; + bool measure; + uint64_t last_measure, last_data; + DMX_CHANNEL_TYPE dmx_type; + std::vector pesfds; + struct dmx_sct_filter_params s_flt; + struct dmx_pes_filter_params p_flt; + public: + + bool Open(DMX_CHANNEL_TYPE pes_type, void * x = NULL, int y = 0); + void Close(void); + bool Start(bool record = false); + bool Stop(void); + int Read(unsigned char *buff, int len, int Timeout = 0); + bool sectionFilter(unsigned short pid, const unsigned char * const filter, const unsigned char * const mask, int len, int Timeout = 0, const unsigned char * const negmask = NULL); + bool pesFilter(const unsigned short pid); + void SetSyncMode(AVSYNC_TYPE mode); + void * getBuffer(); + void * getChannel(); + DMX_CHANNEL_TYPE getChannelType(void) { return dmx_type; }; + bool addPid(unsigned short pid); + void getSTC(int64_t * STC); + int getUnit(void); + static bool SetSource(int unit, int source); + // TD only functions + int getFD(void) { return fd; }; /* needed by cPlayback class */ + void removePid(unsigned short Pid); /* needed by cRecord class */ + std::vector getPesPids(void) { return pesfds; }; + // + cDemux(int num = 0); + ~cDemux(); +}; + +#endif //__DEMUX_H diff --git a/generic-pc/hardware_caps.c b/generic-pc/hardware_caps.c new file mode 100644 index 0000000..36b2b35 --- /dev/null +++ b/generic-pc/hardware_caps.c @@ -0,0 +1,37 @@ +/* + * determine the capabilities of the hardware. + * part of libstb-hal + * + * (C) 2010-2012 Stefan Seyfried + * + * License: GPL v2 or later + */ + +#include +#include +#include +#include +#include +#include +#include + +static int initialized = 0; +static hw_caps_t caps; + +hw_caps_t *get_hwcaps(void) +{ + if (initialized) + return ∩︀ + + memset(&caps, 0, sizeof(hw_caps_t)); + + initialized = 1; + caps.can_shutdown = 1; /* for testing */ + caps.display_type = HW_DISPLAY_LINE_TEXT; + caps.has_HDMI = 1; + caps.display_xres = 8; + strcpy(caps.boxvendor, "Generic"); + strcpy(caps.boxname, "PC"); + + return ∩︀ +} diff --git a/generic-pc/init.cpp b/generic-pc/init.cpp new file mode 100644 index 0000000..273cc04 --- /dev/null +++ b/generic-pc/init.cpp @@ -0,0 +1,21 @@ +#include +#include "init_lib.h" +#include "lt_debug.h" +#define lt_debug(args...) _lt_debug(TRIPLE_DEBUG_INIT, NULL, args) +#define lt_info(args...) _lt_info(TRIPLE_DEBUG_INIT, NULL, args) + +static bool initialized = false; + +void init_td_api() +{ + if (!initialized) + lt_debug_init(); + lt_info("%s begin, initialized=%d, debug=0x%02x\n", __func__, (int)initialized, debuglevel); + initialized = true; +} + +void shutdown_td_api() +{ + lt_info("%s, initialized = %d\n", __func__, (int)initialized); + initialized = false; +} diff --git a/generic-pc/init_lib.h b/generic-pc/init_lib.h new file mode 100644 index 0000000..d9a6f09 --- /dev/null +++ b/generic-pc/init_lib.h @@ -0,0 +1,5 @@ +#ifndef __INIT_TD_H +#define __INIT_TD_H +void init_td_api(); +void shutdown_td_api(); +#endif diff --git a/generic-pc/playback.cpp b/generic-pc/playback.cpp new file mode 100644 index 0000000..0aa2a75 --- /dev/null +++ b/generic-pc/playback.cpp @@ -0,0 +1,74 @@ +#include + +#include "playback.h" + +static const char * FILENAME = "playback-dummy"; + +bool cPlayback::Open(playmode_t) +{ + return 0; +} + +void cPlayback::Close(void) +{ +} + +bool cPlayback::Start(char * filename, unsigned short vpid, int vtype, unsigned short apid, bool ac3, int duration) +{ + printf("%s:%s - filename=%s vpid=%u vtype=%d apid=%u ac3=%d duration=%i\n", + FILENAME, __func__, filename, vpid, vtype, apid, ac3, duration); + return true; +} + +bool cPlayback::SetAPid(unsigned short pid, bool /*ac3*/) +{ + printf("%s:%s pid %i\n", FILENAME, __func__, pid); + return true; +} + +bool cPlayback::SetSPid(int pid) +{ + printf("%s:%s pid %i\n", FILENAME, __func__, pid); + return true; +} + +bool cPlayback::SetSpeed(int speed) +{ + printf("%s:%s playing %d speed %d\n", FILENAME, __func__, playing, speed); + return true; +} + +bool cPlayback::GetSpeed(int &/*speed*/) const +{ + return true; +} + +bool cPlayback::GetPosition(int &position, int &duration) +{ + printf("%s:%s %d %d\n", FILENAME, __func__, position, duration); + position = 0; + duration = 0; + return true; +} + +bool cPlayback::SetPosition(int position, bool) +{ + printf("%s:%s %d\n", FILENAME, __func__,position); + return true; +} + +void cPlayback::FindAllPids(uint16_t *, unsigned short *, uint16_t *numpida, std::string *) +{ + printf("%s:%s\n", FILENAME, __func__); + *numpida = 0; +} + +cPlayback::cPlayback(int /*num*/) +{ + printf("%s:%s\n", FILENAME, __func__); +} + +cPlayback::~cPlayback() +{ + printf("%s:%s\n", FILENAME, __func__); +} diff --git a/generic-pc/playback.h b/generic-pc/playback.h new file mode 100644 index 0000000..862f444 --- /dev/null +++ b/generic-pc/playback.h @@ -0,0 +1,34 @@ +#ifndef __PLAYBACK_H +#define __PLAYBACK_H + +#include +#include + +typedef enum { + PLAYMODE_TS = 0, + PLAYMODE_FILE, +} playmode_t; + +class cPlayback +{ + private: + bool playing; + public: + bool Open(playmode_t PlayMode); + void Close(void); + bool Start(char * filename, unsigned short vpid, int vtype, unsigned short apid, bool ac3, int duration); + bool Stop(void); + bool SetAPid(unsigned short pid, bool ac3); + bool SetSPid(int pid); + bool SetSpeed(int speed); + bool GetSpeed(int &speed) const; + bool GetPosition(int &position, int &duration); + bool SetPosition(int position, bool absolute = false); + void FindAllPids(uint16_t *apids, unsigned short *ac3flags, uint16_t *numpida, std::string *language); + void FindAllSPids(int *spids, uint16_t *numpids, std::string *language); + // + cPlayback(int num = 0); + ~cPlayback(); +}; + +#endif diff --git a/generic-pc/pwrmngr.cpp b/generic-pc/pwrmngr.cpp new file mode 120000 index 0000000..cee9acb --- /dev/null +++ b/generic-pc/pwrmngr.cpp @@ -0,0 +1 @@ +../libspark/pwrmngr.cpp \ No newline at end of file diff --git a/generic-pc/pwrmngr.h b/generic-pc/pwrmngr.h new file mode 120000 index 0000000..e63e97b --- /dev/null +++ b/generic-pc/pwrmngr.h @@ -0,0 +1 @@ +../libspark/pwrmngr.h \ No newline at end of file diff --git a/generic-pc/record.cpp b/generic-pc/record.cpp new file mode 120000 index 0000000..4daae8d --- /dev/null +++ b/generic-pc/record.cpp @@ -0,0 +1 @@ +../libspark/record.cpp \ No newline at end of file diff --git a/generic-pc/record_lib.h b/generic-pc/record_lib.h new file mode 120000 index 0000000..1ec9332 --- /dev/null +++ b/generic-pc/record_lib.h @@ -0,0 +1 @@ +../libspark/record_lib.h \ No newline at end of file diff --git a/generic-pc/video.cpp b/generic-pc/video.cpp new file mode 100644 index 0000000..4ca5f66 --- /dev/null +++ b/generic-pc/video.cpp @@ -0,0 +1,150 @@ +/* + * (C) 2002-2003 Andreas Oberritter + * (C) 2010-2012 Stefan Seyfried + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA + */ + +/* this is a dummy implementation with no functionality at all */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include "video_lib.h" +#define VIDEO_DEVICE "/dev/dvb/adapter0/video0" +#include "lt_debug.h" +#define lt_debug(args...) _lt_debug(TRIPLE_DEBUG_VIDEO, this, args) +#define lt_info(args...) _lt_info(TRIPLE_DEBUG_VIDEO, this, args) +#define lt_debug_c(args...) _lt_debug(TRIPLE_DEBUG_VIDEO, NULL, args) +#define lt_info_c(args...) _lt_info(TRIPLE_DEBUG_VIDEO, NULL, args) + +#define fop(cmd, args...) ({ \ + int _r; \ + if (fd >= 0) { \ + if ((_r = ::cmd(fd, args)) < 0) \ + lt_info(#cmd"(fd, "#args")\n"); \ + else \ + lt_debug(#cmd"(fd, "#args")\n");\ + } \ + else { _r = fd; } \ + _r; \ +}) + +cVideo * videoDecoder = NULL; +int system_rev = 0; + +cVideo::cVideo(int, void *, void *) +{ + lt_debug("%s\n", __FUNCTION__); +} + +cVideo::~cVideo(void) +{ +} + +int cVideo::setAspectRatio(int, int) +{ + return 0; +} + +int cVideo::getAspectRatio(void) +{ + return 1; +} + +int cVideo::setCroppingMode(int) +{ + return 0; +} + +int cVideo::Start(void *, unsigned short, unsigned short, void *) +{ + return 0; +} + +int cVideo::Stop(bool) +{ + return 0; +} + +int cVideo::setBlank(int) +{ + return 1; +} + +int cVideo::SetVideoSystem(int, bool) +{ + return 0; +} + +int cVideo::getPlayState(void) +{ + return VIDEO_PLAYING; +} + +void cVideo::SetVideoMode(analog_mode_t) +{ +} + +void cVideo::ShowPicture(const char *) +{ +} + +void cVideo::StopPicture() +{ +} + +void cVideo::Standby(unsigned int) +{ +} + +int cVideo::getBlank(void) +{ + return 0; +} + +void cVideo::Pig(int, int, int, int, int, int) +{ +} + +void cVideo::getPictureInfo(int &width, int &height, int &rate) +{ + width = 720; + height = 576; + rate = 50; +} + +void cVideo::SetSyncMode(AVSYNC_TYPE) +{ +}; + +int cVideo::SetStreamType(VIDEO_FORMAT) +{ + return 0; +} diff --git a/generic-pc/video_lib.h b/generic-pc/video_lib.h new file mode 100644 index 0000000..c3979e0 --- /dev/null +++ b/generic-pc/video_lib.h @@ -0,0 +1,168 @@ +#ifndef _VIDEO_TD_H +#define _VIDEO_TD_H + +#include +#include "../common/cs_types.h" + +typedef enum { + ANALOG_SD_RGB_CINCH = 0x00, + ANALOG_SD_YPRPB_CINCH, + ANALOG_HD_RGB_CINCH, + ANALOG_HD_YPRPB_CINCH, + ANALOG_SD_RGB_SCART = 0x10, + ANALOG_SD_YPRPB_SCART, + ANALOG_HD_RGB_SCART, + ANALOG_HD_YPRPB_SCART, + ANALOG_SCART_MASK = 0x10 +} analog_mode_t; + + +typedef enum { + VIDEO_FORMAT_MPEG2 = 0, + VIDEO_FORMAT_MPEG4, + VIDEO_FORMAT_VC1, + VIDEO_FORMAT_JPEG, + VIDEO_FORMAT_GIF, + VIDEO_FORMAT_PNG +} VIDEO_FORMAT; + +typedef enum { + VIDEO_SD = 0, + VIDEO_HD, + VIDEO_120x60i, + VIDEO_320x240i, + VIDEO_1440x800i, + VIDEO_360x288i +} VIDEO_DEFINITION; + +typedef enum { + VIDEO_FRAME_RATE_23_976 = 0, + VIDEO_FRAME_RATE_24, + VIDEO_FRAME_RATE_25, + VIDEO_FRAME_RATE_29_97, + VIDEO_FRAME_RATE_30, + VIDEO_FRAME_RATE_50, + VIDEO_FRAME_RATE_59_94, + VIDEO_FRAME_RATE_60 +} VIDEO_FRAME_RATE; + +typedef enum { + DISPLAY_AR_1_1, + DISPLAY_AR_4_3, + DISPLAY_AR_14_9, + DISPLAY_AR_16_9, + DISPLAY_AR_20_9, + DISPLAY_AR_RAW, +} DISPLAY_AR; + +typedef enum { + DISPLAY_AR_MODE_PANSCAN = 0, + DISPLAY_AR_MODE_LETTERBOX, + DISPLAY_AR_MODE_NONE, + DISPLAY_AR_MODE_PANSCAN2 +} DISPLAY_AR_MODE; + +typedef enum { + VIDEO_DB_DR_NEITHER = 0, + VIDEO_DB_ON, + VIDEO_DB_DR_BOTH +} VIDEO_DB_DR; + +typedef enum { + VIDEO_PLAY_STILL = 0, + VIDEO_PLAY_CLIP, + VIDEO_PLAY_TRICK, + VIDEO_PLAY_MOTION, + VIDEO_PLAY_MOTION_NO_SYNC +} VIDEO_PLAY_MODE; + +typedef enum { + VIDEO_STD_NTSC, + VIDEO_STD_SECAM, + VIDEO_STD_PAL, + VIDEO_STD_480P, + VIDEO_STD_576P, + VIDEO_STD_720P60, + VIDEO_STD_1080I60, + VIDEO_STD_720P50, + VIDEO_STD_1080I50, + VIDEO_STD_1080P30, + VIDEO_STD_1080P24, + VIDEO_STD_1080P25, + VIDEO_STD_AUTO, + VIDEO_STD_1080P50, /* SPARK only */ + VIDEO_STD_MAX = VIDEO_STD_1080P50 +} VIDEO_STD; + +/* not used, for dummy functions */ +typedef enum { + VIDEO_HDMI_CEC_MODE_OFF = 0, + VIDEO_HDMI_CEC_MODE_TUNER, + VIDEO_HDMI_CEC_MODE_RECORDER +} VIDEO_HDMI_CEC_MODE; + +typedef enum +{ + VIDEO_CONTROL_BRIGHTNESS = 0, + VIDEO_CONTROL_CONTRAST, + VIDEO_CONTROL_SATURATION, + VIDEO_CONTROL_HUE, + VIDEO_CONTROL_SHARPNESS, + VIDEO_CONTROL_MAX = VIDEO_CONTROL_SHARPNESS +} VIDEO_CONTROL; + + +class cVideo +{ + public: + /* constructor & destructor */ + cVideo(int mode, void *, void *); + ~cVideo(void); + + void * GetTVEnc() { return NULL; }; + void * GetTVEncSD() { return NULL; }; + + /* aspect ratio */ + int getAspectRatio(void); + void getPictureInfo(int &width, int &height, int &rate); + int setAspectRatio(int aspect, int mode); + + /* cropping mode */ + int setCroppingMode(int x = 0 /*vidDispMode_t x = VID_DISPMODE_NORM*/); + + /* get play state */ + int getPlayState(void); + + /* blank on freeze */ + int getBlank(void); + int setBlank(int enable); + + /* change video play state. Parameters are all unused. */ + int Start(void *PcrChannel = NULL, unsigned short PcrPid = 0, unsigned short VideoPid = 0, void *x = NULL); + int Stop(bool blank = true); + bool Pause(void); + + /* set video_system */ + int SetVideoSystem(int video_system, bool remember = true); + int SetStreamType(VIDEO_FORMAT type); + void SetSyncMode(AVSYNC_TYPE mode); + bool SetCECMode(VIDEO_HDMI_CEC_MODE) { return true; }; + void SetCECAutoView(bool) { return; }; + void SetCECAutoStandby(bool) { return; }; + void ShowPicture(const char * fname); + void StopPicture(); + void Standby(unsigned int bOn); + void Pig(int x, int y, int w, int h, int osd_w = 1064, int osd_h = 600); + void SetControl(int, int) { return; }; + void setContrast(int val); + void SetVideoMode(analog_mode_t mode); + void SetDBDR(int) { return; }; + void SetAudioHandle(void *) { return; }; + void SetAutoModes(int [VIDEO_STD_MAX]) { return; }; + int OpenVBI(int) { return 0; }; + int CloseVBI(void) { return 0; }; + int StartVBI(unsigned short) { return 0; }; + int StopVBI(void) { return 0; }; +}; + +#endif diff --git a/include/audio_td.h b/include/audio_td.h index 08610ea..d645238 100644 --- a/include/audio_td.h +++ b/include/audio_td.h @@ -5,6 +5,8 @@ #include "../libspark/audio_lib.h" #elif HAVE_AZBOX_HARDWARE #include "../azbox/audio_lib.h" +#elif HAVE_GENERIC_HARDWARE +#include "../generic-pc/audio_lib.h" #else #error neither HAVE_TRIPLEDRAGON nor HAVE_SPARK_HARDWARE defined #endif diff --git a/include/cs_api.h b/include/cs_api.h index 1e9aded..90a65a7 100644 --- a/include/cs_api.h +++ b/include/cs_api.h @@ -5,6 +5,8 @@ #include "../libspark/cs_api.h" #elif HAVE_AZBOX_HARDWARE #include "../azbox/cs_api.h" +#elif HAVE_GENERIC_HARDWARE +#include "../generic-pc/cs_api.h" #else #error neither HAVE_TRIPLEDRAGON nor HAVE_SPARK_HARDWARE defined #endif diff --git a/include/dmx_td.h b/include/dmx_td.h index 2c7ccff..1ff4b7e 100644 --- a/include/dmx_td.h +++ b/include/dmx_td.h @@ -5,6 +5,8 @@ #include "../libspark/dmx_lib.h" #elif HAVE_AZBOX_HARDWARE #include "../azbox/dmx_lib.h" +#elif HAVE_GENERIC_HARDWARE +#include "../generic-pc/dmx_lib.h" #else #error neither HAVE_TRIPLEDRAGON nor HAVE_SPARK_HARDWARE defined #endif diff --git a/include/playback_td.h b/include/playback_td.h index 1b37edb..9ff93c3 100644 --- a/include/playback_td.h +++ b/include/playback_td.h @@ -5,6 +5,8 @@ #include "../libspark/playback_libeplayer3.h" #elif HAVE_AZBOX_HARDWARE #include "../azbox/playback.h" +#elif HAVE_GENERIC_HARDWARE +#include "../generic-pc/playback.h" #else #error neither HAVE_TRIPLEDRAGON nor HAVE_SPARK_HARDWARE defined #endif diff --git a/include/pwrmngr.h b/include/pwrmngr.h index 1988484..c878544 100644 --- a/include/pwrmngr.h +++ b/include/pwrmngr.h @@ -5,6 +5,8 @@ #include "../libspark/pwrmngr.h" #elif HAVE_AZBOX_HARDWARE #include "../azbox/pwrmngr.h" +#elif HAVE_GENERIC_HARDWARE +#include "../generic-pc/pwrmngr.h" #else #error neither HAVE_TRIPLEDRAGON nor HAVE_SPARK_HARDWARE defined #endif diff --git a/include/record_td.h b/include/record_td.h index f2bd72a..e29b527 100644 --- a/include/record_td.h +++ b/include/record_td.h @@ -5,6 +5,8 @@ #include "../libspark/record_lib.h" #elif HAVE_AZBOX_HARDWARE #include "../azbox/record_lib.h" +#elif HAVE_GENERIC_HARDWARE +#include "../generic-pc/record_lib.h" #else #error neither HAVE_TRIPLEDRAGON nor HAVE_SPARK_HARDWARE defined #endif diff --git a/include/video_td.h b/include/video_td.h index cc6bfcb..1e81f2f 100644 --- a/include/video_td.h +++ b/include/video_td.h @@ -5,6 +5,8 @@ #include "../libspark/video_lib.h" #elif HAVE_AZBOX_HARDWARE #include "../azbox/video_lib.h" +#elif HAVE_GENERIC_HARDWARE +#include "../generic-pc/video_lib.h" #else #error neither HAVE_TRIPLEDRAGON nor HAVE_SPARK_HARDWARE defined #endif