TRIPLEDRAGON: libtriple deleted

Origin commit data
------------------
Branch: master
Commit: 6254833c17
Author: max_10 <max_10@gmx.de>
Date: 2020-10-01 (Thu, 01 Oct 2020)

Origin message was:
------------------
- TRIPLEDRAGON: libtriple deleted

------------------
No further description and justification available within origin commit message!

------------------
This commit was generated by Migit
This commit is contained in:
max_10
2020-10-01 23:18:17 +02:00
committed by vanhofen
parent 020a515fa6
commit 77d6fbeebb
26 changed files with 6 additions and 5446 deletions

View File

@@ -75,9 +75,9 @@ AC_SYS_LARGEFILE
AC_DEFUN([TUXBOX_BOXTYPE], [ AC_DEFUN([TUXBOX_BOXTYPE], [
AC_ARG_WITH(boxtype, AC_ARG_WITH(boxtype,
AS_HELP_STRING([--with-boxtype], [valid values: generic, tripledragon, spark, duckbox, armbox, mipsbox]), AS_HELP_STRING([--with-boxtype], [valid values: generic, spark, duckbox, armbox, mipsbox]),
[case "${withval}" in [case "${withval}" in
generic|tripledragon|spark|duckbox|armbox|mipsbox) generic|spark|duckbox|armbox|mipsbox)
BOXTYPE="$withval" BOXTYPE="$withval"
;; ;;
*) *)
@@ -138,7 +138,6 @@ AC_SUBST(BOXTYPE)
AC_SUBST(BOXMODEL) AC_SUBST(BOXMODEL)
AM_CONDITIONAL(BOXTYPE_GENERIC, test "$BOXTYPE" = "generic") AM_CONDITIONAL(BOXTYPE_GENERIC, test "$BOXTYPE" = "generic")
AM_CONDITIONAL(BOXTYPE_TRIPLE, test "$BOXTYPE" = "tripledragon")
AM_CONDITIONAL(BOXTYPE_SPARK, test "$BOXTYPE" = "spark") AM_CONDITIONAL(BOXTYPE_SPARK, test "$BOXTYPE" = "spark")
AM_CONDITIONAL(BOXTYPE_DUCKBOX, test "$BOXTYPE" = "duckbox") AM_CONDITIONAL(BOXTYPE_DUCKBOX, test "$BOXTYPE" = "duckbox")
AM_CONDITIONAL(BOXTYPE_ARMBOX, test "$BOXTYPE" = "armbox") AM_CONDITIONAL(BOXTYPE_ARMBOX, test "$BOXTYPE" = "armbox")
@@ -202,8 +201,6 @@ AM_CONDITIONAL(BOXMODEL_VUDUO, test "$BOXMODEL" = "vuduo")
if test "$BOXTYPE" = "generic"; then if test "$BOXTYPE" = "generic"; then
AC_DEFINE(HAVE_GENERIC_HARDWARE, 1, [building for a generic device like a standard PC]) AC_DEFINE(HAVE_GENERIC_HARDWARE, 1, [building for a generic device like a standard PC])
elif test "$BOXTYPE" = "tripledragon"; then
AC_DEFINE(HAVE_TRIPLEDRAGON, 1, [building for a tripledragon])
elif test "$BOXTYPE" = "spark"; then elif test "$BOXTYPE" = "spark"; then
AC_DEFINE(HAVE_SPARK_HARDWARE, 1, [building for a goldenmedia 990 or edision pingulux]) AC_DEFINE(HAVE_SPARK_HARDWARE, 1, [building for a goldenmedia 990 or edision pingulux])
AC_DEFINE(HAVE_SH4_HARDWARE, 1, [building for a sh4 box]) AC_DEFINE(HAVE_SH4_HARDWARE, 1, [building for a sh4 box])

View File

@@ -115,7 +115,6 @@ libeplayer3-sh4/Makefile
libgeneric-pc/Makefile libgeneric-pc/Makefile
libraspi/Makefile libraspi/Makefile
libspark/Makefile libspark/Makefile
libtriple/Makefile
tools/Makefile tools/Makefile
]) ])

View File

@@ -1,7 +1,5 @@
#include <config.h> #include <config.h>
#if HAVE_TRIPLEDRAGON #if HAVE_DUCKBOX_HARDWARE
#include "../libtriple/audio_td.h"
#elif HAVE_DUCKBOX_HARDWARE
#include "../libduckbox/audio_lib.h" #include "../libduckbox/audio_lib.h"
#include "../libduckbox/audio_mixer.h" #include "../libduckbox/audio_mixer.h"
#elif HAVE_SPARK_HARDWARE #elif HAVE_SPARK_HARDWARE

View File

@@ -1,7 +1,5 @@
#include <config.h> #include <config.h>
#if HAVE_TRIPLEDRAGON #if HAVE_DUCKBOX_HARDWARE
#include "../libtriple/playback_td.h"
#elif HAVE_DUCKBOX_HARDWARE
#include "../libduckbox/playback_libeplayer3.h" #include "../libduckbox/playback_libeplayer3.h"
#elif HAVE_SPARK_HARDWARE #elif HAVE_SPARK_HARDWARE
#include "../libspark/playback_libeplayer3.h" #include "../libspark/playback_libeplayer3.h"

View File

@@ -1,7 +1,5 @@
#include <config.h> #include <config.h>
#if HAVE_TRIPLEDRAGON #if HAVE_DUCKBOX_HARDWARE
#include "../libtriple/record_td.h"
#elif HAVE_DUCKBOX_HARDWARE
#include "../libduckbox/record_lib.h" #include "../libduckbox/record_lib.h"
#elif HAVE_SPARK_HARDWARE #elif HAVE_SPARK_HARDWARE
#include "../libspark/record_lib.h" #include "../libspark/record_lib.h"

View File

@@ -1,7 +1,5 @@
#include <config.h> #include <config.h>
#if HAVE_TRIPLEDRAGON #if HAVE_DUCKBOX_HARDWARE
#include "../libtriple/video_td.h"
#elif HAVE_DUCKBOX_HARDWARE
#include "../libduckbox/video_lib.h" #include "../libduckbox/video_lib.h"
#elif HAVE_SPARK_HARDWARE #elif HAVE_SPARK_HARDWARE
#include "../libspark/video_lib.h" #include "../libspark/video_lib.h"

View File

@@ -1,22 +0,0 @@
noinst_LTLIBRARIES = libtriple.la
AM_CPPFLAGS = \
-I$(top_srcdir)/common \
-I$(top_srcdir)/include \
@DIRECTFB_CFLAGS@
AM_CXXFLAGS = -fno-rtti -fno-exceptions -fno-strict-aliasing
AM_LDFLAGS = \
-lrt \
@DIRECTFB_LIBS@
libtriple_la_SOURCES = \
hardware_caps.c \
lt_dfbinput.cpp \
dmx_td.cpp \
video_td.cpp \
audio_td.cpp \
init_td.cpp \
playback_td.cpp \
pwrmngr.cpp \
record_td.cpp

View File

@@ -1,75 +0,0 @@
libtriple reimplements the interfaces of the libcoolstrem library for
the Tripledragon receiver.
There are a few debugging or configuration helpers which affect the
way libtriple does some things. They are all configured by exporting
environment variables, which are described here:
TRIPLE_NOSCART=1 - makes neutrino *not* do any voltage switching on
SCART pin 8, probably not useful for anyone but me
TRIPLE_LCDBACKLIGHT=1 - makes the LCD backlight stay on in standby,
may disturb others
HAL_DEBUG=... - controls various debugging levels in libtriple
valid values for the different component:
audio 0x01
video 0x02
demux 0x04
play 0x08
power 0x10
init 0x20
ca 0x40
record 0x80
all 0xff
multiple levels are added / ORed together, so if you want to
debug record and playback code, do "export HAL_DEBUG=0x88"
for audio & video use HAL_DEBUG=0x3
DSP_DEVICE
MIX_DEVICE - alternative audio devices for the audioplayer and internet
radio. Those are used to output music to e.g. USB audio devices.
Here is what you need to do:
* look in /dev/sound which devices are already there. Probably
/dev/sound/dsp and /dev/sound/mixer, created by the tdoss driver
* make sure that the USB HC driver is loaded:
modprobe ohci-hcd
* load the USB audio driver:
modprobe audio
* plug in your USB audio device, check with "dmesg" that it is
recognised by the kernel
* look in /dev/sound which new devices are there. Probably it's
/dev/sound/dsp1 and /dev/sound/mixer1. If there are more - well
it's time to experiment ;)
* export DSP_DEVICE=/dev/sound/dsp1 and MIX_DEVICE=/dev/sound/mixer1
(of course the devices you found in the last step)
* from the same shell you exported the variables, start neutrino
(make sure that an already running neutrino is stopped before you
do that)
* start the audioplayer, play a track. Look for log lines like
[LT:106b5788:audio ] PrepareClipPlay: dsp_dev /dev/sound/dsp1 mix_dev /dev/sound/mixer1
* if it works - fine :-)
* if it does not work, look for:
PrepareClipPlay: DSP_DEVICE is set (/dev/sound/dsp1) but cannot be opened, fall back to /dev/sound/dsp
PrepareClipPlay: dsp_dev /dev/sound/dsp mix_dev /dev/sound/mixer1
PrepareClipPlay: open mixer /dev/sound/mixer1 failed (No such file or directory)
* this basically means that the device is not there. Different errors
will get different messages - I cannot trigger those now, so you'll
need to find them out by yourself ;)
* another possible messag you may get is:
PrepareClipPlay: more than one mixer control: devmask 00000021 stereo 00000021
This means that your device has more than one mixer. The set bit
numbers in the devmask are the different mixers, in this case
it would be number 0 and 5. To select one of those, export
MIX_NUMBER=5 or MIX_NUMBER=0 (this code is untested, there may
be bugs)
So now I found out what devices to use, but how do I make that permanent?
That's easy:
* create or extend /etc/rcS.local with
modprobe ohci-hcd
modprobe audio
* create or extend /etc/profile.local with
export DSP_DEVICE=/dev/sound/dsp1
export MIX_DEVICE=/dev/sound/mixer1
* reboot. Enjoy.

View File

@@ -1,414 +0,0 @@
#include <cstdio>
#include <cstdlib>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <hardware/tddevices.h>
#include <avs/avs_inf.h>
#define AUDIO_DEVICE "/dev/" DEVICE_NAME_AUDIO
#include "audio_td.h"
#include "hal_debug.h"
#define hal_debug(args...) _hal_debug(HAL_DEBUG_AUDIO, this, args)
#define hal_info(args...) _hal_info(HAL_DEBUG_AUDIO, this, args)
#include <linux/soundcard.h>
cAudio * audioDecoder = NULL;
cAudio::cAudio(void *, void *, void *)
{
fd = -1;
clipfd = -1;
mixer_fd = -1;
openDevice();
Muted = false;
}
cAudio::~cAudio(void)
{
closeDevice();
}
void cAudio::openDevice(void)
{
if (fd < 0)
{
if ((fd = open(AUDIO_DEVICE, O_RDWR)) < 0)
hal_info("openDevice: open failed (%m)\n");
fcntl(fd, F_SETFD, FD_CLOEXEC);
do_mute(true, false);
}
else
hal_info("openDevice: already open (fd = %d)\n", fd);
}
void cAudio::closeDevice(void)
{
if (fd >= 0)
close(fd);
fd = -1;
if (clipfd >= 0)
close(clipfd);
clipfd = -1;
if (mixer_fd >= 0)
close(mixer_fd);
mixer_fd = -1;
}
int cAudio::do_mute(bool enable, bool remember)
{
hal_debug("%s(%d, %d)\n", __FUNCTION__, enable, remember);
int avsfd;
int ret;
if (remember)
Muted = enable;
ret = ioctl(fd, MPEG_AUD_SET_MUTE, enable);
if (ret < 0)
hal_info("%s(%d) failed (%m)\n", __FUNCTION__, (int)enable);
/* are we using alternative DSP / mixer? */
if (clipfd != -1 || mixer_fd != -1)
setVolume(volume,volume); /* considers "Muted" variable, "remember"
is basically always true in this context */
avsfd = open("/dev/stb/tdsystem", O_RDONLY);
if (avsfd >= 0)
{
if (enable)
ioctl(avsfd, IOC_AVS_SET_VOLUME, 31);
else
ioctl(avsfd, IOC_AVS_SET_VOLUME, 0);
close(avsfd);
}
return ret;
}
int map_volume(const int volume)
{
unsigned char vol = volume;
if (vol > 100)
vol = 100;
// vol = (invlog63[volume] + 1) / 2;
vol = 31 - vol * 31 / 100;
return vol;
}
int cAudio::setVolume(unsigned int left, unsigned int right)
{
// int avsfd;
int ret;
int vl = map_volume(left);
int vr = map_volume(right);
volume = (left + right) / 2;
int v = map_volume(volume);
if (clipfd != -1 && mixer_fd != -1) {
int tmp = 0;
/* not sure if left / right is correct here, but it is always the same anyways ;-) */
if (! Muted)
tmp = left << 8 | right;
ret = ioctl(mixer_fd, MIXER_WRITE(mixer_num), &tmp);
if (ret == -1)
hal_info("%s: MIXER_WRITE(%d),%04x: %m\n", __func__, mixer_num, tmp);
return ret;
}
// if (settings.volume_type == CControld::TYPE_OST || forcetype == (int)CControld::TYPE_OST)
{
AUDVOL vol;
vol.frontleft = vl;
vol.frontright = vr;
vol.rearleft = vl;
vol.rearright = vr;
vol.center = v;
vol.lfe = v;
ret = ioctl(fd, MPEG_AUD_SET_VOL, &vol);
if (ret < 0)
hal_info("setVolume MPEG_AUD_SET_VOL failed (%m)\n");
return ret;
}
#if 0
else if (settings.volume_type == CControld::TYPE_AVS || forcetype == (int)CControld::TYPE_AVS)
{
if ((avsfd = open(AVS_DEVICE, O_RDWR)) < 0)
perror("[controld] " AVS_DEVICE);
else {
if (ioctl(avsfd, IOC_AVS_SET_VOLUME, v))
perror("[controld] IOC_AVS_SET_VOLUME");
close(avsfd);
return 0;
}
}
fprintf(stderr, "CAudio::setVolume: invalid settings.volume_type = %d\n", settings.volume_type);
return -1;
#endif
}
int cAudio::Start(void)
{
int ret;
ret = ioctl(fd, MPEG_AUD_PLAY);
/* this seems to be not strictly necessary since neutrino
re-mutes all the time, but is certainly more correct */
ioctl(fd, MPEG_AUD_SET_MUTE, Muted);
return ret;
}
int cAudio::Stop(void)
{
return ioctl(fd, MPEG_AUD_STOP);
}
bool cAudio::Pause(bool /*Pcm*/)
{
return true;
};
void cAudio::SetSyncMode(AVSYNC_TYPE Mode)
{
hal_debug("%s %d\n", __FUNCTION__, Mode);
switch (Mode)
{
case 0:
ioctl(fd, MPEG_AUD_SYNC_OFF);
break;
default:
ioctl(fd, MPEG_AUD_SYNC_ON);
break;
}
};
void cAudio::SetStreamType(AUDIO_FORMAT type)
{
int bypass_disable;
hal_debug("%s %d\n", __FUNCTION__, type);
StreamType = type;
if (StreamType != AUDIO_FMT_DOLBY_DIGITAL && StreamType != AUDIO_FMT_MPEG && StreamType != AUDIO_FMT_MPG1)
hal_info("%s unhandled AUDIO_FORMAT %d\n", __FUNCTION__, StreamType);
bypass_disable = (StreamType != AUDIO_FMT_DOLBY_DIGITAL);
setBypassMode(bypass_disable);
if (StreamType == AUDIO_FMT_MPEG)
ioctl(fd, MPEG_AUD_SET_STREAM_TYPE, AUD_STREAM_TYPE_PES);
if (StreamType == AUDIO_FMT_MPG1)
ioctl(fd, MPEG_AUD_SET_STREAM_TYPE, AUD_STREAM_TYPE_MPEG1);
};
int cAudio::setChannel(int channel)
{
hal_debug("%s %d\n", __FUNCTION__, channel);
return 0;
};
int cAudio::PrepareClipPlay(int ch, int srate, int bits, int little_endian)
{
int fmt;
unsigned int devmask, stereo, usable;
const char *dsp_dev = getenv("DSP_DEVICE");
const char *mix_dev = getenv("MIX_DEVICE");
hal_debug("%s ch %d srate %d bits %d le %d\n", __FUNCTION__, ch, srate, bits, little_endian);
if (clipfd >= 0) {
hal_info("%s: clipfd already opened (%d)\n", __FUNCTION__, clipfd);
return -1;
}
mixer_num = -1;
mixer_fd = -1;
/* a different DSP device can be given with DSP_DEVICE and MIX_DEVICE
* if this device cannot be opened, we fall back to the internal TD OSS device
* Example:
* modprobe ohci-hcd
* modprobe audio
* export DSP_DEVICE=/dev/sound/dsp1
* export MIX_DEVICE=/dev/sound/mixer1
* neutrino
*/
if ((!dsp_dev) || (access(dsp_dev, W_OK))) {
if (dsp_dev)
hal_info("%s: DSP_DEVICE is set (%s) but cannot be opened,"
" fall back to /dev/sound/dsp\n", __func__, dsp_dev);
dsp_dev = "/dev/sound/dsp";
}
hal_info("%s: dsp_dev %s mix_dev %s\n", __func__, dsp_dev, mix_dev); /* NULL mix_dev is ok */
/* the tdoss dsp driver seems to work only on the second open(). really. */
clipfd = open(dsp_dev, O_WRONLY);
close(clipfd);
clipfd = open(dsp_dev, O_WRONLY);
if (clipfd < 0) {
hal_info("%s open %s: %m\n", dsp_dev, __FUNCTION__);
return -1;
}
fcntl(clipfd, F_SETFD, FD_CLOEXEC);
/* no idea if we ever get little_endian == 0 */
if (little_endian)
fmt = AFMT_S16_BE;
else
fmt = AFMT_S16_LE;
if (ioctl(clipfd, SNDCTL_DSP_SETFMT, &fmt))
perror("SNDCTL_DSP_SETFMT");
if (ioctl(clipfd, SNDCTL_DSP_CHANNELS, &ch))
perror("SNDCTL_DSP_CHANNELS");
if (ioctl(clipfd, SNDCTL_DSP_SPEED, &srate))
perror("SNDCTL_DSP_SPEED");
if (ioctl(clipfd, SNDCTL_DSP_RESET))
perror("SNDCTL_DSP_RESET");
if (!mix_dev)
return 0;
mixer_fd = open(mix_dev, O_RDWR);
if (mixer_fd < 0) {
hal_info("%s: open mixer %s failed (%m)\n", __func__, mix_dev);
/* not a real error */
return 0;
}
if (ioctl(mixer_fd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) {
hal_info("%s: SOUND_MIXER_READ_DEVMASK %m\n", __func__);
devmask = 0;
}
if (ioctl(mixer_fd, SOUND_MIXER_READ_STEREODEVS, &stereo) == -1) {
hal_info("%s: SOUND_MIXER_READ_STEREODEVS %m\n", __func__);
stereo = 0;
}
usable = devmask & stereo;
if (usable == 0) {
hal_info("%s: devmask: %08x stereo: %08x, no usable dev :-(\n",
__func__, devmask, stereo);
close(mixer_fd);
mixer_fd = -1;
return 0; /* TODO: should we treat this as error? */
}
/* __builtin_popcount needs GCC, it counts the set bits... */
if (__builtin_popcount (usable) != 1) {
/* TODO: this code is not yet tested as I have only single-mixer devices... */
hal_info("%s: more than one mixer control: devmask %08x stereo %08x\n"
"%s: querying MIX_NUMBER environment variable...\n",
__func__, devmask, stereo, __func__);
const char *tmp = getenv("MIX_NUMBER");
if (tmp)
mixer_num = atoi(tmp);
hal_info("%s: mixer_num is %d -> device %08x\n",
__func__, (mixer_num >= 0) ? (1 << mixer_num) : 0);
/* no error checking, you'd better know what you are doing... */
} else {
mixer_num = 0;
while (!(usable & 0x01)) {
mixer_num++;
usable >>= 1;
}
}
setVolume(volume, volume);
return 0;
};
int cAudio::WriteClip(unsigned char *buffer, int size)
{
int ret;
// hal_debug("cAudio::%s\n", __FUNCTION__);
if (clipfd <= 0) {
hal_info("%s: clipfd not yet opened\n", __FUNCTION__);
return -1;
}
ret = write(clipfd, buffer, size);
if (ret < 0)
hal_info("%s: write error (%m)\n", __FUNCTION__);
return ret;
};
int cAudio::StopClip()
{
hal_debug("%s\n", __FUNCTION__);
if (clipfd <= 0) {
hal_info("%s: clipfd not yet opened\n", __FUNCTION__);
return -1;
}
close(clipfd);
clipfd = -1;
if (mixer_fd >= 0)
close(mixer_fd);
mixer_fd = -1;
setVolume(volume, volume);
return 0;
};
void cAudio::getAudioInfo(int &type, int &layer, int &freq, int &bitrate, int &mode)
{
hal_debug("%s\n", __FUNCTION__);
unsigned int atype;
static const int freq_mpg[] = {44100, 48000, 32000, 0};
static const int freq_ac3[] = {48000, 44100, 32000, 0};
scratchl2 i;
if (ioctl(fd, MPEG_AUD_GET_DECTYP, &atype) < 0)
perror("cAudio::getAudioInfo MPEG_AUD_GET_DECTYP");
if (ioctl(fd, MPEG_AUD_GET_STATUS, &i) < 0)
perror("cAudio::getAudioInfo MPEG_AUD_GET_STATUS");
type = atype;
#if 0
/* this does not work, some of the values are negative?? */
AMPEGStatus A;
memcpy(&A, &i.word00, sizeof(i.word00));
layer = A.audio_mpeg_layer;
mode = A.audio_mpeg_mode;
bitrate = A.audio_mpeg_bitrate;
switch(A.audio_mpeg_frequency)
#endif
/* layer and bitrate are not used anyway... */
layer = 0; //(i.word00 >> 17) & 3;
bitrate = 0; //(i.word00 >> 12) & 3;
switch (type)
{
case 0: /* MPEG */
mode = (i.word00 >> 6) & 3;
freq = freq_mpg[(i.word00 >> 10) & 3];
break;
case 1: /* AC3 */
mode = (i.word00 >> 28) & 7;
freq = freq_ac3[(i.word00 >> 16) & 3];
break;
default:
mode = 0;
freq = 0;
}
//fprintf(stderr, "type: %d layer: %d freq: %d bitrate: %d mode: %d\n", type, layer, freq, bitrate, mode);
};
void cAudio::SetSRS(int /*iq_enable*/, int /*nmgr_enable*/, int /*iq_mode*/, int /*iq_level*/)
{
hal_debug("%s\n", __FUNCTION__);
};
void cAudio::SetSpdifDD(bool enable)
{
hal_debug("%s %d\n", __FUNCTION__, enable);
};
void cAudio::ScheduleMute(bool On)
{
hal_debug("%s %d\n", __FUNCTION__, On);
};
void cAudio::EnableAnalogOut(bool enable)
{
hal_debug("%s %d\n", __FUNCTION__, enable);
};
void cAudio::setBypassMode(bool disable)
{
hal_debug("%s %d\n", __FUNCTION__, disable);
/* disable = true: audio is MPEG, disable = false: audio is AC3 */
if (disable)
{
ioctl(fd, MPEG_AUD_SET_MODE, AUD_MODE_MPEG);
return;
}
/* dvb2001 does always set AUD_MODE_DTS before setting AUD_MODE_AC3,
this might be some workaround, so we do the same... */
ioctl(fd, MPEG_AUD_SET_MODE, AUD_MODE_DTS);
ioctl(fd, MPEG_AUD_SET_MODE, AUD_MODE_AC3);
return;
/* all those ioctl aways return "invalid argument", but they seem to
work anyway, so there's no use in checking the return value */
}

View File

@@ -1,98 +0,0 @@
/* public header file */
#ifndef __AUDIO_TD_H__
#define __AUDIO_TD_H__
#include <hardware/aud/aud_inf.h>
#include "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() { return false; };
void SetHdmiDD(bool) { return; };
void SetSpdifDD(bool enable);
void ScheduleMute(bool On);
void EnableAnalogOut(bool enable);
};
#endif // __AUDIO_TD_H__

View File

@@ -1,654 +0,0 @@
/*
* cDemux implementation for the Tripledragon dbs3000 receiver
*
* (C) 2010-2013 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, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <inttypes.h>
#include <unistd.h>
#include <cstring>
#include <cstdio>
#include <string>
#include <hardware/tddevices.h>
#include "dmx_hal.h"
#include "hal_debug.h"
/* Ugh... see comment in destructor for details... */
#include "video_td.h"
extern cVideo *videoDecoder;
#define hal_debug(args...) _hal_debug(HAL_DEBUG_DEMUX, this, args)
#define hal_info(args...) _hal_info(HAL_DEBUG_DEMUX, this, args)
#define dmx_err(_errfmt, _errstr, _revents) do { \
hal_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, flt); \
} 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 as used to the TD devices */
static const char *devname[] = {
"/dev/" DEVICE_NAME_DEMUX "0",
"/dev/" DEVICE_NAME_DEMUX "1",
"/dev/" DEVICE_NAME_DEMUX "2",
};
/* uuuugly */
static int dmx_tp_count = 0;
#define MAX_TS_COUNT 1
typedef struct dmx_pdata {
bool measure;
int last_measure;
int last_data;
int devnum;
bool running;
} dmx_pdata;
#define P ((dmx_pdata *)pdata)
cDemux::cDemux(int n)
{
if (n < 0 || n > 2)
{
hal_info("%s ERROR: n invalid (%d)\n", __FUNCTION__, n);
num = 0;
}
else
num = n;
fd = -1;
pdata = calloc(1, sizeof(dmx_pdata));
P->measure = false;
P->last_measure = 0;
P->last_data = 0;
P->running = false;
}
cDemux::~cDemux()
{
hal_debug("%s #%d fd: %d\n", __FUNCTION__, num, fd);
Close();
free(pdata);
pdata = NULL;
}
bool cDemux::Open(DMX_CHANNEL_TYPE pes_type, void * /*hVideoBuffer*/, int uBufferSize)
{
P->devnum = num;
int flags = O_RDWR;
if (fd > -1)
hal_info("%s FD ALREADY OPENED? fd = %d\n", __FUNCTION__, fd);
if (pes_type == DMX_TP_CHANNEL)
{
/* see neutrino's src/gui/streaminfo2.cpp for the buffer size */
if (num == 0 && uBufferSize == 3 * 3008 * 62) /* streaminfo measurement, let's cheat... */
{
hal_info("%s num=0 and DMX_TP_CHANNEL => measurement demux\n", __func__);
P->devnum = 2; /* demux 0 is used for live, demux 1 for recording */
P->measure = true;
P->last_measure = 0;
P->last_data = 0;
flags |= O_NONBLOCK;
}
else
{
/* it looks like the drivers can only do one TS at a time */
if (dmx_tp_count >= MAX_TS_COUNT)
{
hal_info("%s too many DMX_TP_CHANNEL requests :-(\n", __FUNCTION__);
dmx_type = DMX_INVALID;
fd = -1;
return false;
}
dmx_tp_count++;
P->devnum = dmx_tp_count;
}
}
fd = open(devname[P->devnum], flags);
if (fd < 0)
{
hal_info("%s %s: %m\n", __FUNCTION__, devname[P->devnum]);
return false;
}
fcntl(fd, F_SETFD, FD_CLOEXEC);
hal_debug("%s #%d pes_type: %s(%d), uBufferSize: %d dev:%s fd: %d\n", __func__,
num, DMX_T[pes_type], pes_type, uBufferSize, devname[P->devnum] + strlen("/dev/stb/"), fd);
dmx_type = pes_type;
if (!pesfds.empty())
{
hal_info("%s ERROR! pesfds not empty!\n", __FUNCTION__); /* TODO: error handling */
return false;
}
if (pes_type == DMX_TP_CHANNEL)
{
if (P->measure)
return true;
struct demux_bucket_para bp;
bp.unloader.unloader_type = UNLOADER_TYPE_TRANSPORT;
bp.unloader.threshold = 128;
ioctl(fd, DEMUX_SELECT_SOURCE, INPUT_FROM_CHANNEL0);
ioctl(fd, DEMUX_SET_BUFFER_SIZE, 230400);
ioctl(fd, DEMUX_FILTER_BUCKET_SET, &bp);
return true;
}
if (uBufferSize > 0)
{
/* probably uBufferSize == 0 means "use default size". TODO: find a reasonable default */
if (ioctl(fd, DEMUX_SET_BUFFER_SIZE, uBufferSize) < 0)
hal_info("%s DEMUX_SET_BUFFER_SIZE failed (%m)\n", __FUNCTION__);
}
buffersize = uBufferSize;
return true;
}
void cDemux::Close(void)
{
hal_debug("%s #%d, fd = %d\n", __FUNCTION__, num, fd);
if (fd < 0)
{
hal_info("%s #%d: not open!\n", __FUNCTION__, num);
return;
}
for (std::vector<pes_pids>::const_iterator i = pesfds.begin(); i != pesfds.end(); ++i)
{
hal_debug("%s stopping and closing demux fd %d pid 0x%04x\n", __FUNCTION__, (*i).fd, (*i).pid);
if (ioctl((*i).fd, DEMUX_STOP) < 0)
perror("DEMUX_STOP");
if (close((*i).fd) < 0)
perror("close");
}
pesfds.clear();
ioctl(fd, DEMUX_STOP);
close(fd);
fd = -1;
if (P->measure)
return;
if (dmx_type == DMX_TP_CHANNEL)
{
dmx_tp_count--;
if (dmx_tp_count < 0)
{
hal_info("%s dmx_tp_count < 0!!\n", __func__);
dmx_tp_count = 0;
}
}
}
bool cDemux::Start(bool)
{
if (fd < 0)
{
hal_info("%s #%d: not open!\n", __FUNCTION__, num);
return false;
}
for (std::vector<pes_pids>::const_iterator i = pesfds.begin(); i != pesfds.end(); ++i)
{
hal_debug("%s starting demux fd %d pid 0x%04x\n", __FUNCTION__, (*i).fd, (*i).pid);
if (ioctl((*i).fd, DEMUX_START) < 0)
perror("DEMUX_START");
}
ioctl(fd, DEMUX_START);
P->running = true;
return true;
}
bool cDemux::Stop(void)
{
if (fd < 0)
{
hal_info("%s #%d: not open!\n", __FUNCTION__, num);
return false;
}
for (std::vector<pes_pids>::const_iterator i = pesfds.begin(); i != pesfds.end(); ++i)
{
hal_debug("%s stopping demux fd %d pid 0x%04x\n", __FUNCTION__, (*i).fd, (*i).pid);
if (ioctl((*i).fd, DEMUX_STOP) < 0)
perror("DEMUX_STOP");
}
ioctl(fd, DEMUX_STOP);
P->running = false;
return true;
}
int cDemux::Read(unsigned char *buff, int len, int timeout)
{
#if 0
if (len != 4095 && timeout != 10)
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;
ufds.revents = 0;
if (dmx_type == DMX_INVALID) /* happens, if too many DMX_TP are requested, because */
{ /* nobody checks the return value of Open or Start... */
hal_debug("%s #%d: DMX_INVALID\n", __func__, num);
usleep(timeout * 1000); /* rate-limit the debug message */
errno = EINVAL;
return -1;
}
if (P->measure)
{
if (timeout)
usleep(timeout * 1000);
uint64_t now;
struct timespec t;
clock_gettime(CLOCK_MONOTONIC, &t);
now = t.tv_sec * 1000;
now += t.tv_nsec / 1000000;
if (now - P->last_measure < 333)
return 0;
unsigned char dummy[12];
unsigned long long bit_s = 0;
S_STREAM_MEASURE m;
ioctl(fd, DEMUX_STOP);
rc = read(fd, dummy, 12);
hal_debug("%s measure read: %d\n", __func__, rc);
if (rc == 12)
{
ioctl(fd, DEMUX_GET_MEASURE_TIMING, &m);
if (m.rx_bytes > 0 && m.rx_time_us > 0)
{
// -- current bandwidth in kbit/sec
// --- cast to unsigned long long so it doesn't overflow as
// --- early, add time / 2 before division for correct rounding
/* the correction factor is found out like that:
- with 8000 (guessed), a 256 kbit radio stream shows as 262kbit...
- 8000*256/262 = 7816.793131
BUT! this is only true for some Radio stations (DRS3 for example), for
others (DLF) 8000 does just fine.
bit_s = (m.rx_bytes * 7816793ULL + (m.rx_time_us / 2ULL)) / m.rx_time_us;
*/
bit_s = (m.rx_bytes * 8000ULL + (m.rx_time_us / 2ULL)) / m.rx_time_us;
if (now - P->last_data < 5000)
rc = bit_s * (now - P->last_data) / 8ULL;
else
rc = 0;
hal_debug("%s measure bit_s: %llu rc: %d timediff: %lld\n",
__func__, bit_s, rc, (now - P->last_data));
P->last_data = now;
} else
rc = 0;
}
P->last_measure = now;
ioctl(fd, DEMUX_START);
return rc;
}
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)
//hal_info("%s poll: %m\n", __FUNCTION__);
/* happens, when running under gdb... */
if (errno == EINTR)
goto retry;
return -1;
}
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;
}
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;
struct demux_filter_para s_flt;
memset(&s_flt, 0, sizeof(s_flt));
pid = _pid;
if (len > FILTER_LENGTH - 2)
hal_info("%s #%d: len too long: %d, FILTER_LENGTH: %d\n", __func__, num, len, FILTER_LENGTH);
if (len < 1) /* memcpy below will be unhappy */
hal_info("%s #%d: len too small: %d\n", __func__, num, len);
length = (len + 2 + 1) & 0xfe; /* reportedly, the TD drivers don't handle odd filter */
if (length > FILTER_LENGTH) /* lengths well. So make sure the length is a multiple */
length = FILTER_LENGTH; /* of 2. The unused mask is zeroed anyway. */
flt = filter[0];
s_flt.pid = pid;
s_flt.filter_length = length;
s_flt.filter[0] = filter[0];
s_flt.mask[0] = mask[0];
s_flt.timeout = timeout;
memcpy(&s_flt.filter[3], &filter[1], len - 1);
memcpy(&s_flt.mask[3], &mask[1], len - 1);
if (negmask != NULL)
{
s_flt.positive[0] = negmask[0];
memcpy(&s_flt.positive[3], &negmask[1], len - 1);
}
s_flt.flags = XPDF_IMMEDIATE_START;
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 |= (XPDF_NO_CRC); /* section has no CRC */
//s_flt.pid = 0x0014;
to = 30000;
break;
case 0x71: /* running_status_section */
s_flt.flags |= (XPDF_NO_CRC); /* section has no CRC */
to = 0;
break;
case 0x72: /* stuffing_section */
s_flt.flags |= (XPDF_NO_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 |= (XPDF_NO_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;
}
if (timeout == 0)
s_flt.timeout = to;
hal_debug("%s #%d pid:0x%04hx fd:%d type:%s len:%d/%d to:%d flags:%x flt[0]:%02x\n", __func__, num,
pid, fd, DMX_T[dmx_type], len,s_flt.filter_length, s_flt.timeout,s_flt.flags, s_flt.filter[0]);
#if 0
fprintf(stderr,"filt: ");for(int i=0;i<FILTER_LENGTH;i++)fprintf(stderr,"%02hhx ",s_flt.filter[i]);fprintf(stderr,"\n");
fprintf(stderr,"mask: ");for(int i=0;i<FILTER_LENGTH;i++)fprintf(stderr,"%02hhx ",s_flt.mask [i]);fprintf(stderr,"\n");
fprintf(stderr,"posi: ");for(int i=0;i<FILTER_LENGTH;i++)fprintf(stderr,"%02hhx ",s_flt.positive[i]);fprintf(stderr,"\n");
#endif
ioctl (fd, DEMUX_STOP);
if (ioctl(fd, DEMUX_FILTER_SET, &s_flt) < 0)
return false;
P->running = true;
return true;
}
bool cDemux::pesFilter(const unsigned short _pid)
{
demux_pes_para p_flt;
pid = _pid;
flt = 0;
/* allow PID 0 for web streaming e.g.
* this check originally is from tuxbox cvs but I'm not sure
* what it is good for...
if (pid <= 0x0001 && dmx_type != DMX_PCR_ONLY_CHANNEL)
return false;
*/
if ((pid >= 0x0002 && pid <= 0x000f) || pid >= 0x1fff)
return false;
hal_debug("%s #%d pid: 0x%04hx fd: %d type: %s\n", __FUNCTION__, num, pid, fd, DMX_T[dmx_type]);
if (dmx_type == DMX_TP_CHANNEL && !P->measure)
{
unsigned int n = pesfds.size();
addPid(pid);
return (n != pesfds.size());
}
memset(&p_flt, 0, sizeof(p_flt));
p_flt.pid = pid;
p_flt.output = OUT_DECODER;
switch (dmx_type) {
case DMX_PCR_ONLY_CHANNEL:
p_flt.pesType = DMX_PES_PCR;
break;
case DMX_AUDIO_CHANNEL:
p_flt.pesType = DMX_PES_AUDIO;
break;
case DMX_VIDEO_CHANNEL:
p_flt.pesType = DMX_PES_VIDEO;
break;
case DMX_PES_CHANNEL:
p_flt.unloader.unloader_type = UNLOADER_TYPE_PAYLOAD;
if (buffersize <= 0x10000) // dvbsubtitle, instant delivery...
p_flt.unloader.threshold = 1;
else
p_flt.unloader.threshold = 8; // 1k, teletext
p_flt.pesType = DMX_PES_OTHER;
p_flt.output = OUT_MEMORY;
break;
case DMX_TP_CHANNEL:
/* must be measure == true or we would have returned above */
p_flt.output = OUT_MEMORY;
p_flt.pesType = DMX_PES_OTHER;
p_flt.unloader.threshold = 1;
p_flt.unloader.unloader_type = UNLOADER_TYPE_MEASURE_DUMMY;
ioctl(fd, DEMUX_SET_MEASURE_TIME, 250000);
break;
default:
p_flt.pesType = DMX_PES_OTHER;
}
return (ioctl(fd, DEMUX_FILTER_PES_SET, &p_flt) >= 0);
}
void cDemux::SetSyncMode(AVSYNC_TYPE /*mode*/)
{
hal_debug("%s #%d\n", __FUNCTION__, num);
}
void *cDemux::getBuffer()
{
hal_debug("%s #%d\n", __FUNCTION__, num);
if (P->running)
return (void *)1;
return NULL;
}
void *cDemux::getChannel()
{
hal_debug("%s #%d\n", __FUNCTION__, num);
return NULL;
}
bool cDemux::addPid(unsigned short Pid)
{
pes_pids pfd;
int ret;
struct demux_pes_para p;
if (dmx_type != DMX_TP_CHANNEL)
{
hal_info("%s pes_type %s not implemented yet! pid=%hx\n", __FUNCTION__, DMX_T[dmx_type], Pid);
return false;
}
if (P->measure)
{
hal_info("%s measurement demux -> skipping\n", __func__);
return true;
}
if (fd == -1)
hal_info("%s bucketfd not yet opened? pid=%hx\n", __FUNCTION__, Pid);
pfd.fd = open(devname[P->devnum], O_RDWR);
if (pfd.fd < 0)
{
hal_info("%s #%d Pid = %hx open failed (%m)\n", __FUNCTION__, num, Pid);
return false;
}
fcntl(pfd.fd, F_SETFD, FD_CLOEXEC);
hal_debug("%s #%d Pid = %hx pfd = %d\n", __FUNCTION__, num, Pid, pfd.fd);
p.pid = Pid;
p.pesType = DMX_PES_OTHER;
p.output = OUT_NOTHING;
p.flags = 0;
p.unloader.unloader_type = UNLOADER_TYPE_BUCKET;
p.unloader.threshold = 128;
ioctl(pfd.fd, DEMUX_SELECT_SOURCE, INPUT_FROM_CHANNEL0);
ret = ioctl(pfd.fd, DEMUX_SET_BUFFER_SIZE, 0x10000); // 64k
if (ret == -1)
perror("DEMUX_SET_BUFFER_SIZE");
else
{
ret = ioctl(pfd.fd, DEMUX_FILTER_PES_SET, &p);
if (ret == -1)
perror("DEMUX_FILTER_PES_SET");
}
pfd.pid = Pid;
if (ret != -1)
/* success! */
pesfds.push_back(pfd);
else
/* error! */
close(pfd.fd);
return (ret != -1);
}
void cDemux::removePid(unsigned short Pid)
{
if (dmx_type != DMX_TP_CHANNEL)
{
hal_info("%s pes_type %s not implemented yet! pid=%hx\n", __FUNCTION__, DMX_T[dmx_type], Pid);
return;
}
for (std::vector<pes_pids>::iterator i = pesfds.begin(); i != pesfds.end(); ++i)
{
if ((*i).pid == Pid) {
hal_debug("removePid: removing demux fd %d pid 0x%04x\n", (*i).fd, Pid);
if (ioctl((*i).fd, DEMUX_STOP) < 0)
perror("DEMUX_STOP");
if (close((*i).fd) < 0)
perror("close");
pesfds.erase(i);
return; /* TODO: what if the same PID is there multiple times */
}
}
hal_info("%s pid 0x%04x not found\n", __FUNCTION__, Pid);
}
void cDemux::getSTC(int64_t * STC)
{
hal_debug("%s #%d\n", __FUNCTION__, num);
/* this is a guess, but seems to work... int32_t gives errno 515... */
#define STC_TYPE uint64_t
STC_TYPE stc;
if (ioctl(fd, DEMUX_GET_CURRENT_STC, &stc))
perror("cDemux::getSTC DEMUX_GET_CURRENT_STC");
*STC = (stc >> 32);
}
int cDemux::getUnit(void)
{
hal_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;
}

View File

@@ -1,33 +0,0 @@
/*
* determine the capabilities of the hardware.
* part of libstb-hal
*
* (C) 2010-2012 Stefan Seyfried
*
* License: GPL v2 or later
*/
#include "hardware_caps.h"
static hw_caps_t caps = {
.has_fan = 0,
.has_SCART = 1,
.has_SCART_input = 1,
.has_HDMI = 0,
.has_YUV_cinch = 0,
.can_cpufreq = 1, /* see "elegant" hack in pwrmngr.cpp */
.can_shutdown = 0,
.can_cec = 0,
.display_type = HW_DISPLAY_GFX,
.display_xres = 128,
.display_yres = 64,
.display_can_deepstandby = 0;
.display_has_statusline = 0;
.boxvendor = "Armas",
.boxname = "TripleDragon"
};
hw_caps_t *get_hwcaps(void)
{
return &caps;
}

View File

@@ -1,159 +0,0 @@
#include <stdio.h>
#include "init.h"
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <directfb.h>
extern "C" {
#include <tdpanel/ir_ruwido.h>
#include <hardware/avs/avs_inf.h>
#include <hardware/avs/bios_system_config.h>
}
#include "lt_dfbinput.h"
#include "pwrmngr.h"
#include "hal_debug.h"
#define hal_debug(args...) _hal_debug(HAL_DEBUG_INIT, NULL, args)
#define hal_info(args...) _hal_info(HAL_DEBUG_INIT, NULL, args)
static bool initialized = false;
/* the super interface */
IDirectFB *dfb;
/* the primary surface */
static IDirectFBSurface *primary;
IDirectFBSurface *dfbdest;
static IDirectFBDisplayLayer *layer;
int gfxfd = -1;
#define DFBCHECK(x...) \
err = x; \
if (err != DFB_OK) { \
fprintf(stderr, "init_td.cpp:%d:\n\t", __LINE__); \
DirectFBErrorFatal(#x, err ); \
}
static void dfb_init()
{
int argc = 0;
DFBResult err;
DFBSurfaceDescription dsc;
DFBSurfacePixelFormat pixelformat;
int SW, SH;
DFBCHECK(DirectFBInit(&argc, NULL));
/* neutrino does its own VT handling */
DirectFBSetOption("no-vt-switch", NULL);
DirectFBSetOption("no-vt", NULL);
/* signal handling seems to interfere with neutrino */
DirectFBSetOption("no-sighandler", NULL);
/* if DirectFB grabs the remote, neutrino does not get events */
/* now we handle the input via a DFB thread and push it to
* neutrino via uinput, so reenable tdremote module
DirectFBSetOption("disable-module", "tdremote");
*/
DirectFBSetOption("disable-module", "keyboard");
DirectFBSetOption("disable-module", "linux_input");
DFBCHECK(DirectFBCreate(&dfb));
err = dfb->SetCooperativeLevel(dfb, DFSCL_FULLSCREEN);
if (err)
DirectFBError("Failed to get exclusive access", err);
dsc.flags = DSDESC_CAPS;
dsc.caps = DSCAPS_PRIMARY;
DFBCHECK(dfb->CreateSurface( dfb, &dsc, &primary ));
/* set pixel alpha mode */
dfb->GetDisplayLayer(dfb, DLID_PRIMARY, &layer);
DFBCHECK(layer->SetCooperativeLevel(layer, DLSCL_EXCLUSIVE));
DFBDisplayLayerConfig conf;
DFBCHECK(layer->GetConfiguration(layer, &conf));
conf.flags = DLCONF_OPTIONS;
conf.options = (DFBDisplayLayerOptions)((conf.options & ~DLOP_OPACITY) | DLOP_ALPHACHANNEL);
DFBCHECK(layer->SetConfiguration(layer, &conf));
primary->GetPixelFormat(primary, &pixelformat);
primary->GetSize(primary, &SW, &SH);
primary->Clear(primary, 0, 0, 0, 0);
primary->GetSubSurface(primary, NULL, &dfbdest);
dfbdest->Clear(dfbdest, 0, 0, 0, 0);
start_input_thread(dfb);
}
static void dfb_deinit()
{
stop_input_thread();
dfbdest->Release(dfbdest);
primary->Release(primary);
layer->Release(layer);
dfb->Release(dfb);
}
static void rc_init()
{
/* set remote control address from bootloader config */
int fd = open("/dev/stb/tdsystem", O_RDWR);
struct BIOS_CONFIG_AREA bca;
unsigned short rc_addr = 0xff;
if (ioctl(fd, IOC_AVS_GET_LOADERCONFIG, &bca) != 0)
fprintf(stderr, "%s: IOC_AVS_GET_LOADERCONFIG failed: %m\n", __FUNCTION__);
else
rc_addr = bca.ir_adrs;
close(fd);
fd = open("/dev/stb/tdremote", O_RDWR);
if (ioctl(fd, IOC_IR_SET_ADDRESS, rc_addr) < 0)
fprintf(stderr, "%s: IOC_IR_SET_ADDRESS %d failed: %m\n", __FUNCTION__, rc_addr);
/* short delay in the driver improves responsiveness and reduces spurious
"key up" events during zapping */
//ioctl(fd, IOC_IR_SET_DELAY, 1); TODO: needs more work in rcinput
close(fd);
hal_info("%s rc_addr=0x%02hx\n", __FUNCTION__, rc_addr);
}
void hal_api_init()
{
if (!initialized)
hal_debug_init();
hal_info("%s begin, initialized=%d, debug=0x%02x\n", __FUNCTION__, (int)initialized, debuglevel);
if (!initialized)
{
/* leave standby early, this avoids popping noise on audio device */
cCpuFreqManager f;
f.SetCpuFreq(0); /* CPUFREQ == 0 is the trigger for leaving standby */
/* DirectFB does setpgid(0,0), which disconnects us from controlling terminal
and thus disables e.g. ctrl-C. work around that. */
pid_t pid = getpgid(0);
dfb_init();
if (setpgid(0, pid))
perror("setpgid");
rc_init();
gfxfd = open("/dev/stb/tdgfx", O_RDWR);
if (gfxfd < 0)
perror("open /dev/stb/tdgfx");
fcntl(gfxfd, F_SETFD, FD_CLOEXEC);
}
/* load the module which converts the TD tuner to a Linux-DVB frontend... */
system("/sbin/modprobe td-dvb-frontend");
initialized = true;
hal_info("%s end\n", __FUNCTION__);
}
void hal_api_exit()
{
hal_info("%s, initialized = %d\n", __FUNCTION__, (int)initialized);
if (initialized)
dfb_deinit();
if (gfxfd > -1)
close(gfxfd);
gfxfd = -1;
initialized = false;
}

View File

@@ -1,367 +0,0 @@
/*
* Simulate a linux input device via uinput
* Get td remote events via DirectFB and inject them via uinput
*
* (C) 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, see <http://www.gnu.org/licenses/>.
*/
/* the C++ compiler does not like this code, so let's put it into a
* separate file and compile with gcc insead of g++...
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <linux/ioctl.h>
#include <linux/input.h>
#include <linux/uinput.h>
#include <directfb.h>
#include "lt_dfbinput.h"
/* needed for videodecoder watchdog */
#include "video_td.h"
extern cVideo *videoDecoder;
/* same defines as in neutrino's rcinput.h */
#define KEY_TTTV KEY_FN_1
#define KEY_TTZOOM KEY_FN_2
#define KEY_REVEAL KEY_FN_D
/* only defined in newer kernels / headers... */
#ifndef KEY_ZOOMIN
#define KEY_ZOOMIN KEY_FN_E
#endif
#ifndef KEY_ZOOMOUT
#define KEY_ZOOMOUT KEY_FN_F
#endif
#define DFBCHECK(x...) \
err = x; \
if (err != DFB_OK) { \
fprintf(stderr, "lt_dfbinput.cpp:%d:\n\t", __LINE__); \
DirectFBErrorFatal(#x, err ); \
}
typedef struct _DeviceInfo DeviceInfo;
struct _DeviceInfo {
DFBInputDeviceID device_id;
DFBInputDeviceDescription desc;
DeviceInfo *next;
};
static const int key_list[] = {
KEY_0,
KEY_1,
KEY_2,
KEY_3,
KEY_4,
KEY_5,
KEY_6,
KEY_7,
KEY_8,
KEY_9,
KEY_OK,
KEY_TIME,
KEY_FAVORITES,
KEY_ZOOMOUT,
KEY_ZOOMIN,
KEY_NEXT,
KEY_POWER,
KEY_MUTE,
KEY_MENU,
KEY_EPG,
KEY_INFO,
KEY_EXIT,
KEY_PAGEUP,
KEY_PAGEDOWN,
KEY_LEFT,
KEY_RIGHT,
KEY_UP,
KEY_DOWN,
KEY_VOLUMEUP,
KEY_VOLUMEDOWN,
KEY_RED,
KEY_GREEN,
KEY_YELLOW,
KEY_BLUE,
KEY_TV,
KEY_VIDEO,
KEY_AUDIO,
KEY_AUX,
KEY_TEXT,
KEY_TTTV,
KEY_TTZOOM,
KEY_REVEAL,
KEY_REWIND,
KEY_STOP,
KEY_PAUSE,
KEY_FORWARD,
/* KEY_PREV, */
KEY_EJECTCD,
KEY_RECORD,
/* KEY_NEXT, */
-1
};
static IDirectFBEventBuffer *events;
static DeviceInfo *inputs = NULL;
static pthread_t thread;
static int thread_running;
static DFBEnumerationResult enum_input_device(DFBInputDeviceID device_id,
DFBInputDeviceDescription desc,
void *data)
{
DeviceInfo **devices = (DeviceInfo **)data;
DeviceInfo *device;
device = (DeviceInfo *)malloc(sizeof(DeviceInfo));
device->device_id = device_id;
device->desc = desc;
device->next = *devices;
*devices = device;
return DFENUM_OK;
}
static void *input_thread(void *data)
{
int uinput;
int i;
struct input_event u;
struct uinput_user_dev ud;
FILE *f;
DFBResult err;
IDirectFB *dfb = (IDirectFB *)data;
fprintf(stderr, "DFB input converter thread starting...\n");
/* modprobe does not complain if the module is already loaded... */
system("/sbin/modprobe uinput");
system("/sbin/modprobe evdev");
uinput = open("/dev/misc/uinput", O_WRONLY|O_NDELAY);
if (uinput < 0)
{
fprintf(stderr, "DFB input thread: unable to open /dev/misc/uinput (%m)\n");
return NULL;
}
memset(&u, 0, sizeof(u));
fcntl(uinput, F_SETFD, FD_CLOEXEC);
/* configure the device */
memset(&ud, 0, sizeof(ud));
strncpy(ud.name, "Neutrino TD to Input Device converter", UINPUT_MAX_NAME_SIZE);
ud.id.version = 0x42;
ud.id.vendor = 0x1234;
ud.id.product = 0x5678;
ud.id.bustype = BUS_I2C; /* ?? */
write(uinput, &ud, sizeof(ud));
ioctl(uinput, UI_SET_EVBIT, EV_KEY);
ioctl(uinput, UI_SET_EVBIT, EV_REP);
/* register keys */
for (i = 0; key_list[i] != -1; i++)
ioctl(uinput, UI_SET_KEYBIT, key_list[i]);
if (ioctl(uinput, UI_DEV_CREATE))
{
perror("DFB input thread UI_DEV_CREATE");
close(uinput);
return NULL;
}
/* this is ugly: parse the new input device from /proc/...devices
* and symlink it to /dev/input/nevis_ir... */
#define DEVLINE "I: Bus=0018 Vendor=1234 Product=5678 Version=0042"
f = fopen("/proc/bus/input/devices", "r");
if (f)
{
int found = 0;
int evdev = -1;
size_t n = 0;
char *line = NULL;
char *p;
char newdev[20];
while (getline(&line, &n, f) != -1)
{
switch(line[0])
{
case 'I':
if (strncmp(line, DEVLINE, strlen(DEVLINE)) == 0)
found = 1;
break;
case 'H':
if (! found)
break;
p = strstr(line, " event");
if (! p)
{
evdev = -1;
break;
}
evdev = atoi(p + 6);
sprintf(newdev, "event%d", evdev);
fprintf(stderr, "DFB input thread: symlink /dev/input/nevis_ir to %s\n", newdev);
unlink("/dev/input/nevis_ir");
symlink(newdev, "/dev/input/nevis_ir");
break;
default:
break;
}
if (evdev != -1)
break;
}
fclose(f);
free(line);
}
u.type = EV_KEY;
u.value = 0; /* initialize: first event wil be a key press */
dfb->EnumInputDevices(dfb, enum_input_device, &inputs);
DFBCHECK(dfb->CreateInputEventBuffer(dfb, DICAPS_ALL, DFB_FALSE, &events));
thread_running = 1;
while (thread_running)
{
/* check every 250ms (if a key is pressed on remote, we might
* even check earlier, but it does not really hurt... */
if (videoDecoder)
videoDecoder->VideoParamWatchdog();
if (events->WaitForEventWithTimeout(events, 0, 250) == DFB_TIMEOUT)
continue;
DFBInputEvent e;
while (events->GetEvent(events, DFB_EVENT(&e)) == DFB_OK)
{
#if 0
fprintf(stderr, "type: %x devid: %x flags: %03x "
"key_id: %4x key_sym: %4x keycode: %d\n",
e.type, e.device_id, e.flags,
e.key_id, e.key_symbol, e.key_code);
#endif
switch (e.key_symbol)
{
/* will a lookup table be more efficient? */
case 0x0030: u.code = KEY_0; break;
case 0x0031: u.code = KEY_1; break;
case 0x0032: u.code = KEY_2; break;
case 0x0033: u.code = KEY_3; break;
case 0x0034: u.code = KEY_4; break;
case 0x0035: u.code = KEY_5; break;
case 0x0036: u.code = KEY_6; break;
case 0x0037: u.code = KEY_7; break;
case 0x0038: u.code = KEY_8; break;
case 0x0039: u.code = KEY_9; break;
case 0x000d: u.code = KEY_OK; break;
case 0xf504: u.code = KEY_TIME; break;
case 0xf01a: u.code = KEY_FAVORITES; break; /* blue heart */
case 0xf021: u.code = KEY_ZOOMOUT; break;
case 0xf022: u.code = KEY_ZOOMIN; break;
case 0xf505: u.code = KEY_NEXT; break; /* red hand */
case 0xf00f: u.code = KEY_POWER; break;
case 0xf04e: u.code = KEY_MUTE; break;
case 0xf012: u.code = KEY_MENU; break;
case 0xf01b: u.code = KEY_EPG; break;
case 0xf014: u.code = KEY_INFO; break;
case 0x001b: u.code = KEY_EXIT; break;
case 0xf046: u.code = KEY_PAGEUP; break;
case 0xf047: u.code = KEY_PAGEDOWN; break;
case 0xf000: u.code = KEY_LEFT; break;
case 0xf001: u.code = KEY_RIGHT; break;
case 0xf002: u.code = KEY_UP; break;
case 0xf003: u.code = KEY_DOWN; break;
case 0xf04c: u.code = KEY_VOLUMEUP; break;
case 0xf04d: u.code = KEY_VOLUMEDOWN; break;
case 0xf042: u.code = KEY_RED; break;
case 0xf043: u.code = KEY_GREEN; break;
case 0xf044: u.code = KEY_YELLOW; break;
case 0xf045: u.code = KEY_BLUE; break;
case 0xf027: u.code = KEY_TV; break;
case 0xf035: u.code = KEY_VIDEO; break;
case 0xf033: u.code = KEY_AUDIO; break;
case 0xf034: u.code = KEY_AUX; break;
case 0xf032: u.code = KEY_TEXT; break;
case 0xf501: u.code = KEY_TTTV; break;
case 0xf502: u.code = KEY_TTZOOM; break;
case 0xf503: u.code = KEY_REVEAL; break;
case 0xf059: u.code = KEY_REWIND; break;
case 0xf052: u.code = KEY_STOP; break;
case 0xf051: u.code = KEY_PAUSE; break;
case 0xf05a: u.code = KEY_FORWARD; break;
/* case 0xf05b: u.code = KEY_PREV; break; */
case 0xf057: u.code = KEY_EJECTCD; break;
case 0xf056: u.code = KEY_RECORD; break;
/* case 0xf05c: u.code = KEY_NEXT; break; */
/* front panel left / right */
case 0xf506: u.code = KEY_LEFT; break;
case 0xf507: u.code = KEY_RIGHT; break;
default:
continue;
}
switch (e.type)
{
case 1: u.value = 1; break; /* 1 = key press */
case 2: u.value = 0; break; /* 0 = key release */
/* 2 = key repeat (not used) */
default:
continue;
}
// fprintf(stderr, "uinput write: value: %d code: %d\n", u.value, u.code);
write(uinput, &u, sizeof(u));
}
}
/* clean up */
ioctl(uinput, UI_DEV_DESTROY);
while (inputs) {
DeviceInfo *next = inputs->next;
free(inputs);
inputs = next;
}
events->Release(events);
return NULL;
}
void start_input_thread(IDirectFB *dfb)
{
if (pthread_create(&thread, 0, input_thread, dfb) != 0)
{
perror("DFB input thread pthread_create");
thread_running = 0;
return;
}
/* wait until the device is created before continuing */
while (! thread_running)
usleep(1000);
}
void stop_input_thread(void)
{
if (! thread_running)
return;
thread_running = 0;
pthread_join(thread, NULL);
}

View File

@@ -1,7 +0,0 @@
/* functions from lt_dfbinput.c */
#ifndef __LT_DFB_INPUT_H_
#define __LT_DFB_INPUT_H_
void start_input_thread(IDirectFB *dfb);
void stop_input_thread(void);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,129 +0,0 @@
#ifndef __PLAYBACK_TD_H__
#define __PLAYBACK_TD_H__
#include <inttypes.h>
#include <string>
#include <map>
#include <vector>
/* almost 256kB */
#define INBUF_SIZE (1394 * 188)
#define PESBUF_SIZE (128 * 1024)
typedef enum {
PLAYMODE_TS = 0,
PLAYMODE_FILE,
} playmode_t;
typedef enum {
FILETYPE_UNKNOWN,
FILETYPE_TS,
FILETYPE_MPG,
FILETYPE_VDR
} filetype_t;
typedef enum {
STATE_STOP,
STATE_PLAY,
STATE_PAUSE,
STATE_FF,
STATE_REW,
STATE_INIT
} playstate_t;
typedef struct {
std::string Name;
off_t Size;
} filelist_t;
class cPlayback
{
private:
uint8_t *inbuf;
ssize_t inbuf_pos;
ssize_t inbuf_sync;
uint8_t *pesbuf;
ssize_t pesbuf_pos;
ssize_t inbuf_read(void);
ssize_t read_ts(void);
ssize_t read_mpeg(void);
uint8_t cc[256];
int in_fd;
int video_type;
int playback_speed;
int mSpeed;
playmode_t playMode;
std::vector<filelist_t> filelist; /* for multi-file playback */
bool filelist_auto_add(void);
int mf_open(int fileno);
int mf_close(void);
off_t mf_lseek(off_t pos);
off_t mf_getsize(void);
int curr_fileno;
off_t curr_pos;
off_t last_size;
off_t bytes_per_second;
uint16_t vpid;
uint16_t apid;
bool ac3;
struct AStream {
// uint16_t pid;
bool ac3;
std::string lang; /* not yet really used */
};
std::map<uint16_t, AStream> astreams; /* stores AStream sorted by pid */
int64_t pts_start;
int64_t pts_end;
int64_t _pts_end; /* last good endpts */
int64_t pts_curr;
int64_t get_pts(uint8_t *p, bool pes, int bufsize);
filetype_t filetype;
playstate_t playstate;
off_t seek_to_pts(int64_t pts);
off_t mp_seekSync(off_t pos);
int64_t get_PES_PTS(uint8_t *buf, int len, bool until_eof);
pthread_t thread;
bool thread_started;
public:
cPlayback(int num = 0);
~cPlayback();
void playthread();
bool Open(playmode_t PlayMode);
void Close(void);
bool Start(char *filename, unsigned short vpid, int vtype, unsigned short apid,
int ac3, unsigned int duration);
bool SetAPid(unsigned short pid, int ac3);
bool SetSpeed(int speed);
bool GetSpeed(int &speed) const;
bool GetPosition(int &position, int &duration); /* pos: current time in ms, dur: file length in ms */
bool SetPosition(int position, bool absolute = false); /* position: jump in ms */
void FindAllPids(uint16_t *apids, unsigned short *ac3flags, uint16_t *numpida, std::string *language);
void FindAllSubs(uint16_t *pids, unsigned short *supported, uint16_t *numpida, std::string *language);
bool SelectSubtitles(int pid);
void GetChapters(std::vector<int> &positions, std::vector<std::string> &titles);
#if 0
// Functions that are not used by movieplayer.cpp:
bool Stop(void);
bool GetOffset(off64_t &offset);
bool IsPlaying(void) const { return playing; }
bool IsEnabled(void) const { return enabled; }
void * GetHandle(void);
void * GetDmHandle(void);
int GetCurrPlaybackSpeed(void) const { return nPlaybackSpeed; }
void PlaybackNotify (int Event, void *pData, void *pTag);
void DMNotify(int Event, void *pTsBuf, void *Tag);
#endif
};
#endif // __PLAYBACK_TD_H__

View File

@@ -1,275 +0,0 @@
#include <errno.h>
#include <fcntl.h>
#include <malloc.h>
#include <unistd.h>
#include <sys/types.h>
#include <inttypes.h>
#include <cstdio>
#include <cstring>
#include <pthread.h>
#include "record_td.h"
#include "dmx_hal.h"
#include "hal_debug.h"
#define hal_debug(args...) _hal_debug(HAL_DEBUG_RECORD, this, args)
#define hal_info(args...) _hal_info(HAL_DEBUG_RECORD, this, args)
/* helper function to call the cpp thread loop */
void *execute_record_thread(void *c)
{
cRecord *obj = (cRecord *)c;
obj->RecordThread();
return NULL;
}
cRecord::cRecord(int /*num*/)
{
hal_info("%s\n", __func__);
dmx = NULL;
record_thread_running = false;
file_fd = -1;
exit_flag = RECORD_STOPPED;
}
cRecord::~cRecord()
{
hal_info("%s: calling ::Stop()\n", __func__);
Stop();
hal_info("%s: end\n", __func__);
}
bool cRecord::Open(void)
{
hal_info("%s\n", __func__);
exit_flag = RECORD_STOPPED;
return true;
}
#if 0
// unused
void cRecord::Close(void)
{
hal_info("%s: \n", __func__);
}
#endif
bool cRecord::Start(int fd, unsigned short vpid, unsigned short *apids, int numpids, uint64_t)
{
hal_info("%s: fd %d, vpid 0x%03x\n", __func__, fd, vpid);
int i;
if (!dmx)
dmx = new cDemux(1);
dmx->Open(DMX_TP_CHANNEL, NULL, 0);
dmx->pesFilter(vpid);
for (i = 0; i < numpids; i++)
dmx->addPid(apids[i]);
file_fd = fd;
exit_flag = RECORD_RUNNING;
if (posix_fadvise(file_fd, 0, 0, POSIX_FADV_DONTNEED))
perror("posix_fadvise");
i = pthread_create(&record_thread, 0, execute_record_thread, this);
if (i != 0)
{
exit_flag = RECORD_FAILED_READ;
errno = i;
hal_info("%s: error creating thread! (%m)\n", __func__);
delete dmx;
dmx = NULL;
return false;
}
record_thread_running = true;
return true;
}
bool cRecord::Stop(void)
{
hal_info("%s\n", __func__);
if (exit_flag != RECORD_RUNNING)
hal_info("%s: status not RUNNING? (%d)\n", __func__, exit_flag);
exit_flag = RECORD_STOPPED;
if (record_thread_running)
pthread_join(record_thread, NULL);
record_thread_running = false;
/* We should probably do that from the destructor... */
if (!dmx)
hal_info("%s: dmx == NULL?\n", __func__);
else
delete dmx;
dmx = NULL;
if (file_fd != -1)
close(file_fd);
else
hal_info("%s: file_fd not open??\n", __func__);
file_fd = -1;
return true;
}
bool cRecord::ChangePids(unsigned short /*vpid*/, unsigned short *apids, int numapids)
{
std::vector<pes_pids> pids;
int j;
bool found;
unsigned short pid;
hal_info("%s\n", __func__);
if (!dmx) {
hal_info("%s: DMX = NULL\n", __func__);
return false;
}
pids = dmx->pesfds;
/* the first PID is the video pid, so start with the second PID... */
for (std::vector<pes_pids>::const_iterator i = pids.begin() + 1; i != pids.end(); ++i) {
found = false;
pid = (*i).pid;
for (j = 0; j < numapids; j++) {
if (pid == apids[j]) {
found = true;
break;
}
}
if (!found)
dmx->removePid(pid);
}
for (j = 0; j < numapids; j++) {
found = false;
for (std::vector<pes_pids>::const_iterator i = pids.begin() + 1; i != pids.end(); ++i) {
if ((*i).pid == apids[j]) {
found = true;
break;
}
}
if (!found)
dmx->addPid(apids[j]);
}
return true;
}
bool cRecord::AddPid(unsigned short pid)
{
std::vector<pes_pids> pids;
hal_info("%s: \n", __func__);
if (!dmx) {
hal_info("%s: DMX = NULL\n", __func__);
return false;
}
pids = dmx->pesfds;
for (std::vector<pes_pids>::const_iterator i = pids.begin(); i != pids.end(); ++i) {
if ((*i).pid == pid)
return true; /* or is it an error to try to add the same PID twice? */
}
return dmx->addPid(pid);
}
void cRecord::RecordThread()
{
hal_info("%s: begin\n", __func__);
#define BUFSIZE (1 << 19) /* 512 kB */
ssize_t r = 0;
int buf_pos = 0;
uint8_t *buf;
buf = (uint8_t *)malloc(BUFSIZE);
if (!buf)
{
exit_flag = RECORD_FAILED_MEMORY;
hal_info("%s: unable to allocate buffer! (out of memory)\n", __func__);
}
dmx->Start();
while (exit_flag == RECORD_RUNNING)
{
if (buf_pos < BUFSIZE)
{
r = dmx->Read(buf + buf_pos, BUFSIZE - 1 - buf_pos, 100);
hal_debug("%s: buf_pos %6d r %6d / %6d\n", __func__,
buf_pos, (int)r, BUFSIZE - 1 - buf_pos);
if (r < 0)
{
if (errno != EAGAIN)
{
hal_info("%s: read failed: %m\n", __func__);
exit_flag = RECORD_FAILED_READ;
break;
}
hal_info("%s: EAGAIN\n", __func__);
}
else
buf_pos += r;
}
else
hal_info("%s: buffer full! Overflow?\n", __func__);
if (buf_pos > (BUFSIZE / 3)) /* start writeout */
{
size_t towrite = BUFSIZE / 2;
if (buf_pos < BUFSIZE / 2)
towrite = buf_pos;
r = write(file_fd, buf, towrite);
if (r < 0)
{
exit_flag = RECORD_FAILED_FILE;
hal_info("%s: write error: %m\n", __func__);
break;
}
buf_pos -= r;
memmove(buf, buf + r, buf_pos);
hal_debug("%s: buf_pos %6d w %6d / %6d\n", __func__, buf_pos, (int)r, (int)towrite);
#if 0
if (fdatasync(file_fd))
perror("cRecord::FileThread() fdatasync");
#endif
if (posix_fadvise(file_fd, 0, 0, POSIX_FADV_DONTNEED))
perror("posix_fadvise");
}
}
dmx->Stop();
while (buf_pos > 0) /* write out the unwritten buffer content */
{
r = write(file_fd, buf, buf_pos);
if (r < 0)
{
exit_flag = RECORD_FAILED_FILE;
hal_info("%s: write error: %m\n", __func__);
break;
}
buf_pos -= r;
memmove(buf, buf + r, buf_pos);
}
free(buf);
#if 0
// TODO: do we need to notify neutrino about failing recording?
CEventServer eventServer;
eventServer.registerEvent2(NeutrinoMessages::EVT_RECORDING_ENDED, CEventServer::INITID_NEUTRINO, "/tmp/neutrino.sock");
stream2file_status2_t s;
s.status = exit_flag;
strncpy(s.filename,basename(myfilename),512);
s.filename[511] = '\0';
strncpy(s.dir,dirname(myfilename),100);
s.dir[99] = '\0';
eventServer.sendEvent(NeutrinoMessages::EVT_RECORDING_ENDED, CEventServer::INITID_NEUTRINO, &s, sizeof(s));
printf("[stream2file]: pthreads exit code: %i, dir: '%s', filename: '%s' myfilename: '%s'\n", exit_flag, s.dir, s.filename, myfilename);
#endif
hal_info("%s: end", __func__);
pthread_exit(NULL);
}
int cRecord::GetStatus()
{
/* dummy for now */
return REC_STATUS_OK;
}
void cRecord::ResetStatus()
{
return;
}

View File

@@ -1,44 +0,0 @@
#ifndef __RECORD_TD_H__
#define __RECORD_TD_H__
#include <pthread.h>
#include "dmx_hal.h"
#define REC_STATUS_OK 0
#define REC_STATUS_SLOW 1
#define REC_STATUS_OVERFLOW 2
typedef enum {
RECORD_RUNNING,
RECORD_STOPPED,
RECORD_FAILED_READ, /* failed to read from DMX */
RECORD_FAILED_OVERFLOW, /* cannot write fast enough */
RECORD_FAILED_FILE, /* cannot write to file */
RECORD_FAILED_MEMORY /* out of memory */
} record_state_t;
class cRecord
{
private:
int file_fd;
cDemux *dmx;
pthread_t record_thread;
bool record_thread_running;
record_state_t exit_flag;
int state;
public:
cRecord(int num = 0);
~cRecord();
bool Open();
bool Start(int fd, unsigned short vpid, unsigned short *apids, int numapids, uint64_t ch = 0);
bool Stop(void);
bool AddPid(unsigned short pid);
int GetStatus();
void ResetStatus();
bool ChangePids(unsigned short vpid, unsigned short *apids, int numapids);
void RecordThread();
};
#endif // __RECORD_TD_H__

View File

@@ -1,38 +0,0 @@
/*
* compatibility stuff for Tripledragon audio API
*
* (C) 2009 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; version 2 of the License.
*
* 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef __td_audio_compat_h__
#define __td_audio_compat_h__
#include <aud/aud_inf.h>
// types
typedef enum {
AUDIO_SOURCE_DEMUX = AUD_SOURCE_DEMUX,
AUDIO_SOURCE_MEMORY = AUD_SOURCE_MEMORY
} audio_stream_source_t;
#define audio_channel_select_t audChannel_t
// ioctls
#define AUDIO_CHANNEL_SELECT MPEG_AUD_SELECT_CHANNEL
#define AUDIO_SELECT_SOURCE MPEG_AUD_SELECT_SOURCE
#define AUDIO_PLAY MPEG_AUD_PLAY
#define AUDIO_STOP MPEG_AUD_STOP
#define AUDIO_SET_MUTE MPEG_AUD_SET_MUTE
#endif /* __td_audio_compat_h__ */

View File

@@ -1,45 +0,0 @@
/*
* compatibility stuff for Tripledragon demux API
*
* (C) 2009 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; version 2 of the License.
*
* 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef __td_demux_compat_h__
#define __td_demux_compat_h__
#include <sys/types.h>
#include <xp/xp_osd_user.h>
// types
#define dmx_output_t OutDevice
#define dmx_pes_type_t PesType
#define dmx_sct_filter_params demux_filter_para
#define dmx_pes_filter_params demux_pes_para
#define pes_type pesType
// defines
#define DMX_FILTER_SIZE FILTER_LENGTH
#define DMX_ONESHOT XPDF_ONESHOT
#define DMX_CHECK_CRC 0 // TD checks CRC by default
#define DMX_IMMEDIATE_START XPDF_IMMEDIATE_START
#define DMX_OUT_DECODER OUT_DECODER
// ioctls
#define DMX_SET_FILTER DEMUX_FILTER_SET
#define DMX_SET_PES_FILTER DEMUX_FILTER_PES_SET
#define DMX_START DEMUX_START
#define DMX_STOP DEMUX_STOP
#define DMX_SET_BUFFER_SIZE DEMUX_SET_BUFFER_SIZE
#endif /* __td_demux_compat_h__ */

View File

@@ -1,120 +0,0 @@
/*
* compatibility stuff for Tripledragon frontend API
*
* (C) 2009 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; version 2 of the License.
*
* 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef __td_frontend_compat_h__
#define __td_frontend_compat_h__
#ifdef __cplusplus
extern "C" {
#endif
#include <tdtuner/tuner_inf.h>
#ifdef __cplusplus
}
#endif
/* I know that those are different. But functions that get a
dvb_frontend_parameters struct passed on dbox/dreambox will most likely
get a tunersetup struct on TD, so it keeps the differences in headers
and function prototypes small. Of course, the functions itself will have
#ifdef TRIPLEDRAGON or similar... */
#define dvb_frontend_parameters tunersetup
/* compat stuff for settings.cpp */
enum {
INVERSION_OFF,
INVERSION_ON,
INVERSION_AUTO
};
typedef enum fe_code_rate {
FEC_NONE = 0,
FEC_1_2,
FEC_2_3,
FEC_3_4,
FEC_4_5,
FEC_5_6,
FEC_6_7,
FEC_7_8,
FEC_8_9,
FEC_AUTO
} fe_code_rate_t;
enum td_code_rate {
TD_FEC_AUTO = 0,
TD_FEC_1_2,
TD_FEC_2_3,
TD_FEC_3_4,
TD_FEC_5_6,
TD_FEC_7_8
};
typedef enum fe_sec_tone_mode {
SEC_TONE_ON,
SEC_TONE_OFF
} fe_sec_tone_mode_t;
typedef enum fe_sec_voltage {
SEC_VOLTAGE_13,
SEC_VOLTAGE_18,
SEC_VOLTAGE_OFF
} fe_sec_voltage_t;
typedef enum fe_sec_mini_cmd {
SEC_MINI_A,
SEC_MINI_B
} fe_sec_mini_cmd_t;
struct dvb_diseqc_master_cmd {
unsigned char msg [6]; /* { framing, address, command, data [3] } */
unsigned char msg_len; /* valid values are 3...6 */
};
typedef enum fe_type {
FE_QPSK,
FE_QAM,
FE_OFDM,
FE_ATSC
} fe_type_t;
struct dvb_frontend_info {
// char name[128];
fe_type_t type;
#if 0
__u32 frequency_min;
__u32 frequency_max;
__u32 frequency_stepsize;
__u32 frequency_tolerance;
__u32 symbol_rate_min;
__u32 symbol_rate_max;
__u32 symbol_rate_tolerance; /* ppm */
__u32 notifier_delay; /* DEPRECATED */
fe_caps_t caps;
#endif
};
struct dvb_frontend_event {
fe_status_t status;
tunersetup parameters;
};
#ifdef _DVBFRONTEND_H_
#error _DVBFRONTEND_H_ included
#endif
#endif /* __td_frontend_compat_h__ */

View File

@@ -1,93 +0,0 @@
/*
* compatibility stuff for conversion of Tripledragon API values to DVB API
* and vice versa
*
* (C) 2009 Stefan Seyfried
*
* Released under the GPL V2.
*/
#ifndef _td_value_compat_
#define _td_value_compat_
#undef FE_GET_INFO
#undef FE_READ_BER
#undef FE_READ_SIGNAL_STRENGTH
#undef FE_READ_SNR
#undef FE_READ_UNCORRECTED_BLOCKS
#undef FE_GET_EVENT
#undef FE_READ_STATUS
#undef FE_SET_PROPERTY
#undef FE_GET_EVENT
#undef FE_GET_EVENT
#undef FE_SET_PROPERTY
#undef FE_SET_TONE
#undef FE_ENABLE_HIGH_LNB_VOLTAGE
#undef FE_SET_VOLTAGE
#undef FE_DISEQC_SEND_MASTER_CMD
#undef FE_DISEQC_SEND_BURST
/* hack, linux/dvb/frontend.h already defines fe_status */
#define fe_status td_fe_status
#define fe_status_t td_fe_status_t
#define FE_HAS_SIGNAL TD_FE_HAS_SIGNAL
#define FE_HAS_CARRIER TD_FE_HAS_CARRIER
#define FE_HAS_VITERBI TD_FE_HAS_VITERBI
#define FE_HAS_SYNC TD_FE_HAS_SYNC
#define FE_HAS_LOCK TD_FE_HAS_LOCK
#define FE_TIMEDOUT TD_FE_TIMEDOUT
#define FE_REINIT TD_FE_REINIT
#include <tdtuner/tuner_inf.h>
#undef fe_status
#undef fe_status_t
#undef FE_HAS_SIGNAL
#undef FE_HAS_CARRIER
#undef FE_HAS_VITERBI
#undef FE_HAS_SYNC
#undef FE_HAS_LOCK
#undef FE_TIMEDOUT
#undef FE_REINIT
enum td_code_rate {
TD_FEC_AUTO = 0,
TD_FEC_1_2,
TD_FEC_2_3,
TD_FEC_3_4,
TD_FEC_5_6,
TD_FEC_7_8
};
static inline unsigned int dvbfec2tdfec(fe_code_rate_t fec)
{
switch (fec) {
case FEC_1_2: // FEC_1_2 ... FEC_3_4 are equal to TD_FEC_1_2 ... TD_FEC_3_4
case FEC_2_3:
case FEC_3_4:
return (unsigned int)fec;
case FEC_5_6:
return TD_FEC_5_6;
case FEC_7_8:
return TD_FEC_7_8;
default:
break;
}
return TD_FEC_AUTO;
}
static inline fe_code_rate_t tdfec2dvbfec(unsigned int tdfec)
{
switch (tdfec)
{
case TD_FEC_1_2:
case TD_FEC_2_3:
case TD_FEC_3_4:
return (fe_code_rate_t)tdfec;
case TD_FEC_5_6:
return FEC_5_6;
case TD_FEC_7_8:
return FEC_7_8;
default:
break;
}
return FEC_AUTO;
}
#endif /* _td_value_compat_ */

View File

@@ -1,46 +0,0 @@
/*
* compatibility stuff for Tripledragon video API
*
* (C) 2009 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; version 2 of the License.
*
* 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __td_video_compat_h__
#define __td_video_compat_h__
#include <vid/vid_inf.h>
// types
#define video_format_t vidDispSize_t
#define video_displayformat_t vidDispMode_t
typedef enum {
VIDEO_SOURCE_DEMUX = VID_SOURCE_DEMUX,
VIDEO_SOURCE_MEMORY = VID_SOURCE_MEMORY
} video_stream_source_t;
typedef enum {
VIDEO_STOPPED, /* Video is stopped */
VIDEO_PLAYING, /* Video is currently playing */
VIDEO_FREEZED /* Video is freezed */
} video_play_state_t;
//#define video_play_state_t vidState_t
// ioctls
#define VIDEO_SET_SYSTEM MPEG_VID_SET_DISPFMT
#define VIDEO_SET_FORMAT MPEG_VID_SET_DISPSIZE
#define VIDEO_SET_DISPLAY_FORMAT MPEG_VID_SET_DISPMODE
#define VIDEO_SELECT_SOURCE MPEG_VID_SELECT_SOURCE
#define VIDEO_PLAY MPEG_VID_PLAY
#define VIDEO_STOP MPEG_VID_STOP
#define VIDEO_SET_BLANK MPEG_VID_SET_BLANK
#endif /* __td_video_compat_h__ */

File diff suppressed because it is too large Load Diff

View File

@@ -1,196 +0,0 @@
#ifndef __VIDEO_TD_H__
#define __VIDEO_TD_H__
#include <hardware/vid/vid_inf.h>
#define video_format_t vidDispSize_t
//#define video_displayformat_t vidDispMode_t
#include "cs_types.h"
#include "dmx_td.h"
#define STB_HAL_VIDEO_HAS_GETSCREENIMAGE 1
typedef enum {
ANALOG_SD_RGB_SCART = 0x00,
ANALOG_SD_YPRPB_SCART,
ANALOG_HD_RGB_SCART,
ANALOG_HD_YPRPB_SCART,
ANALOG_SD_RGB_CINCH = 0x80,
ANALOG_SD_YPRPB_CINCH,
ANALOG_HD_RGB_CINCH,
ANALOG_HD_YPRPB_CINCH,
} 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 = VID_DISPFMT_NTSC, /* 0 */
VIDEO_STD_PAL = VID_DISPFMT_PAL, /* 1 */
VIDEO_STD_SECAM = VID_DISPFMT_SECAM, /* 4 */
VIDEO_STD_1080I50 = VIDEO_STD_PAL, /* hack, this is used in neutrino settings default */
VIDEO_STD_MAX = VIDEO_STD_SECAM + 1
} VIDEO_STD;
typedef enum {
VIDEO_STOPPED, /* Video is stopped */
VIDEO_PLAYING, /* Video is currently playing */
VIDEO_FREEZED /* Video is freezed */
} video_play_state_t;
/* 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
{
private:
/* video device */
int fd;
/* apparently we cannot query the driver's state
=> remember it */
video_play_state_t playstate;
vidDispMode_t croppingMode;
vidOutFmt_t outputformat;
int scartvoltage;
int z[2]; /* zoomvalue for 4:3 (0) and 16:9 (1) in percent */
int *zoomvalue;
void *blank_data[2]; /* we store two blank MPEGs (PAL/NTSC) in there */
int blank_size[2];
VIDEO_FORMAT StreamType;
VIDEO_DEFINITION VideoDefinition;
DISPLAY_AR DisplayAR;
VIDEO_PLAY_MODE SyncMode;
DISPLAY_AR_MODE ARMode;
VIDEO_DB_DR eDbDr;
DISPLAY_AR PictureAR;
VIDEO_FRAME_RATE FrameRate;
void routeVideo(int standby);
int video_standby;
public:
/* constructor & destructor */
cVideo(int mode, void *, void *, unsigned int unit = 0);
~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(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; };
bool 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; };
int setZoom(int);
void VideoParamWatchdog(void);
void setContrast(int val);
void SetVideoMode(analog_mode_t mode);
void SetDBDR(int) { return; };
void SetAudioHandle(void *) { return; };
void FastForwardMode(int mode = 0);
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; };
void SetDemux(cDemux *dmx);
bool GetScreenImage(unsigned char * &data, int &xres, int &yres, bool get_video = true, bool get_osd = false, bool scale_to_video = false);
};
#endif // __VIDEO_TD_H__