mirror of
https://github.com/tuxbox-neutrino/libstb-hal.git
synced 2025-08-26 23:13:16 +02:00
- TRIPLEDRAGON: libtriple deleted
This commit is contained in:
@@ -12,12 +12,6 @@ libstb_hal_la_LIBADD = \
|
|||||||
#libstb_hal_test_LDADD = libstb-hal.la
|
#libstb_hal_test_LDADD = libstb-hal.la
|
||||||
|
|
||||||
# there has to be a better way to do this...
|
# there has to be a better way to do this...
|
||||||
if BOXTYPE_TRIPLE
|
|
||||||
SUBDIRS += libtriple
|
|
||||||
libstb_hal_la_LIBADD += \
|
|
||||||
libtriple/libtriple.la
|
|
||||||
endif
|
|
||||||
|
|
||||||
if BOXTYPE_GENERIC
|
if BOXTYPE_GENERIC
|
||||||
if BOXMODEL_RASPI
|
if BOXMODEL_RASPI
|
||||||
SUBDIRS += libraspi
|
SUBDIRS += libraspi
|
||||||
|
@@ -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])
|
||||||
|
@@ -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
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
@@ -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"
|
||||||
|
@@ -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"
|
||||||
|
@@ -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"
|
||||||
|
@@ -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
|
|
@@ -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.
|
|
@@ -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 */
|
|
||||||
}
|
|
@@ -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__
|
|
@@ -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;
|
|
||||||
}
|
|
@@ -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 ∩︀
|
|
||||||
}
|
|
@@ -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;
|
|
||||||
}
|
|
@@ -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);
|
|
||||||
}
|
|
@@ -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
@@ -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__
|
|
@@ -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;
|
|
||||||
}
|
|
@@ -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__
|
|
@@ -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__ */
|
|
@@ -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__ */
|
|
@@ -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__ */
|
|
@@ -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_ */
|
|
@@ -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
@@ -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__
|
|
Reference in New Issue
Block a user