diff --git a/acinclude.m4 b/acinclude.m4 index ed5b571..0fa62a2 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -75,9 +75,9 @@ AC_SYS_LARGEFILE AC_DEFUN([TUXBOX_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 - generic|tripledragon|spark|duckbox|armbox|mipsbox) + generic|spark|duckbox|armbox|mipsbox) BOXTYPE="$withval" ;; *) @@ -138,7 +138,6 @@ AC_SUBST(BOXTYPE) AC_SUBST(BOXMODEL) AM_CONDITIONAL(BOXTYPE_GENERIC, test "$BOXTYPE" = "generic") -AM_CONDITIONAL(BOXTYPE_TRIPLE, test "$BOXTYPE" = "tripledragon") AM_CONDITIONAL(BOXTYPE_SPARK, test "$BOXTYPE" = "spark") AM_CONDITIONAL(BOXTYPE_DUCKBOX, test "$BOXTYPE" = "duckbox") AM_CONDITIONAL(BOXTYPE_ARMBOX, test "$BOXTYPE" = "armbox") @@ -202,8 +201,6 @@ AM_CONDITIONAL(BOXMODEL_VUDUO, test "$BOXMODEL" = "vuduo") if test "$BOXTYPE" = "generic"; then 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 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]) diff --git a/configure.ac b/configure.ac index c1ca1f1..42c3f2c 100644 --- a/configure.ac +++ b/configure.ac @@ -115,7 +115,6 @@ libeplayer3-sh4/Makefile libgeneric-pc/Makefile libraspi/Makefile libspark/Makefile -libtriple/Makefile tools/Makefile ]) diff --git a/include/audio_hal.h b/include/audio_hal.h index e223568..56c5118 100644 --- a/include/audio_hal.h +++ b/include/audio_hal.h @@ -1,7 +1,5 @@ #include -#if HAVE_TRIPLEDRAGON -#include "../libtriple/audio_td.h" -#elif HAVE_DUCKBOX_HARDWARE +#if HAVE_DUCKBOX_HARDWARE #include "../libduckbox/audio_lib.h" #include "../libduckbox/audio_mixer.h" #elif HAVE_SPARK_HARDWARE diff --git a/include/playback_hal.h b/include/playback_hal.h index e526648..41943b5 100644 --- a/include/playback_hal.h +++ b/include/playback_hal.h @@ -1,7 +1,5 @@ #include -#if HAVE_TRIPLEDRAGON -#include "../libtriple/playback_td.h" -#elif HAVE_DUCKBOX_HARDWARE +#if HAVE_DUCKBOX_HARDWARE #include "../libduckbox/playback_libeplayer3.h" #elif HAVE_SPARK_HARDWARE #include "../libspark/playback_libeplayer3.h" diff --git a/include/record_hal.h b/include/record_hal.h index 8ebaba0..911c012 100644 --- a/include/record_hal.h +++ b/include/record_hal.h @@ -1,7 +1,5 @@ #include -#if HAVE_TRIPLEDRAGON -#include "../libtriple/record_td.h" -#elif HAVE_DUCKBOX_HARDWARE +#if HAVE_DUCKBOX_HARDWARE #include "../libduckbox/record_lib.h" #elif HAVE_SPARK_HARDWARE #include "../libspark/record_lib.h" diff --git a/include/video_hal.h b/include/video_hal.h index c960b15..d351ae9 100644 --- a/include/video_hal.h +++ b/include/video_hal.h @@ -1,7 +1,5 @@ #include -#if HAVE_TRIPLEDRAGON -#include "../libtriple/video_td.h" -#elif HAVE_DUCKBOX_HARDWARE +#if HAVE_DUCKBOX_HARDWARE #include "../libduckbox/video_lib.h" #elif HAVE_SPARK_HARDWARE #include "../libspark/video_lib.h" diff --git a/libtriple/Makefile.am b/libtriple/Makefile.am deleted file mode 100644 index 4d14aaa..0000000 --- a/libtriple/Makefile.am +++ /dev/null @@ -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 diff --git a/libtriple/README.libtriple b/libtriple/README.libtriple deleted file mode 100644 index 1f756dc..0000000 --- a/libtriple/README.libtriple +++ /dev/null @@ -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. diff --git a/libtriple/audio_td.cpp b/libtriple/audio_td.cpp deleted file mode 100644 index 67c293e..0000000 --- a/libtriple/audio_td.cpp +++ /dev/null @@ -1,414 +0,0 @@ -#include -#include -#include -#include -#include - - -#include -#include -#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 - -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 */ -} diff --git a/libtriple/audio_td.h b/libtriple/audio_td.h deleted file mode 100644 index cb06a19..0000000 --- a/libtriple/audio_td.h +++ /dev/null @@ -1,98 +0,0 @@ -/* public header file */ - -#ifndef __AUDIO_TD_H__ -#define __AUDIO_TD_H__ - -#include -#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__ diff --git a/libtriple/dmx_td.cpp b/libtriple/dmx_td.cpp deleted file mode 100644 index cd1abc7..0000000 --- a/libtriple/dmx_td.cpp +++ /dev/null @@ -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 . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#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::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::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::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;irunning = 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::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; -} diff --git a/libtriple/hardware_caps.c b/libtriple/hardware_caps.c deleted file mode 100644 index 3d6112c..0000000 --- a/libtriple/hardware_caps.c +++ /dev/null @@ -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 ∩︀ -} diff --git a/libtriple/init_td.cpp b/libtriple/init_td.cpp deleted file mode 100644 index f8758d8..0000000 --- a/libtriple/init_td.cpp +++ /dev/null @@ -1,159 +0,0 @@ -#include - -#include "init.h" -#include -#include -#include -#include -#include -#include -#include - -#include - -extern "C" { -#include -#include -#include -} -#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; -} diff --git a/libtriple/lt_dfbinput.cpp b/libtriple/lt_dfbinput.cpp deleted file mode 100644 index e61915a..0000000 --- a/libtriple/lt_dfbinput.cpp +++ /dev/null @@ -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 . - */ - -/* 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 -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include -#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); -} diff --git a/libtriple/lt_dfbinput.h b/libtriple/lt_dfbinput.h deleted file mode 100644 index 1a74fb2..0000000 --- a/libtriple/lt_dfbinput.h +++ /dev/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 diff --git a/libtriple/playback_td.cpp b/libtriple/playback_td.cpp deleted file mode 100644 index 3669dc8..0000000 --- a/libtriple/playback_td.cpp +++ /dev/null @@ -1,1506 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "playback_td.h" -#include "dmx_hal.h" -#include "audio_td.h" -#include "video_td.h" -#include "hal_debug.h" -#define hal_debug(args...) _hal_debug(HAL_DEBUG_PLAYBACK, this, args) -#define hal_info(args...) _hal_info(HAL_DEBUG_PLAYBACK, this, args) -#define hal_info_c(args...) _hal_info(HAL_DEBUG_PLAYBACK, NULL, args) - -#include -#define DVR "/dev/" DEVICE_NAME_PVR - -static int mp_syncPES(uint8_t *, int, bool quiet = false); -static int sync_ts(uint8_t *, int); -static inline uint16_t get_pid(uint8_t *buf); -static void *start_playthread(void *c); -static void playthread_cleanup_handler(void *); - -static pthread_cond_t playback_ready_cond = PTHREAD_COND_INITIALIZER; -static pthread_mutex_t playback_ready_mutex = PTHREAD_MUTEX_INITIALIZER; - -static pthread_mutex_t currpos_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t inbufpos_mutex = PTHREAD_MUTEX_INITIALIZER; - -static int dvrfd = -1; -static int streamtype; - -extern cDemux *videoDemux; -extern cDemux *audioDemux; -extern cVideo *videoDecoder; -extern cAudio *audioDecoder; - -static const char *FILETYPE[] = { - "FILETYPE_UNKNOWN", - "FILETYPE_TS", - "FILETYPE_MPG", - "FILETYPE_VDR" -}; - -cPlayback::cPlayback(int) -{ - hal_debug("%s\n", __FUNCTION__); - thread_started = false; - inbuf = NULL; - pesbuf = NULL; - filelist.clear(); - curr_fileno = -1; - in_fd = -1; - streamtype = 0; -} - -cPlayback::~cPlayback() -{ - hal_debug("%s\n", __FUNCTION__); - Close(); -} - - -bool cPlayback::Open(playmode_t mode) -{ - static const char *PMODE[] = { - "PLAYMODE_TS", - "PLAYMODE_FILE" - }; - - hal_debug("%s: PlayMode = %s\n", __FUNCTION__, PMODE[mode]); - thread_started = false; - playMode = mode; - filetype = FILETYPE_TS; - playback_speed = 0; - last_size = 0; - _pts_end = 0; - astreams.clear(); - memset(&cc, 0, 256); - return true; -} - -//Used by Fileplay -void cPlayback::Close(void) -{ - hal_info("%s\n", __FUNCTION__); - playstate = STATE_STOP; - if (thread_started) - { - hal_info("%s: before pthread_join\n", __FUNCTION__); - pthread_join(thread, NULL); - } - thread_started = false; - hal_info("%s: after pthread_join\n", __FUNCTION__); - mf_close(); - filelist.clear(); - - if (inbuf) - free(inbuf); - inbuf = NULL; - if (pesbuf) - free(pesbuf); - pesbuf = NULL; - - /* don't crash */ - if (audioDecoder) - audioDecoder->do_mute(audioDecoder->Muted, false); -} - -bool cPlayback::Start(char *filename, unsigned short vp, int vtype, unsigned short ap, int _ac3, unsigned int) -{ - struct stat s; - off_t r; - vpid = vp; - apid = ap; - ac3 = _ac3; - hal_info("%s name = '%s' vpid 0x%04hx vtype %d apid 0x%04hx ac3 %d filelist.size: %u\n", - __FUNCTION__, filename, vpid, vtype, apid, ac3, filelist.size()); - if (!filelist.empty()) - { - hal_info("filelist not empty?\n"); - return false; - } - if (stat(filename, &s)) - { - hal_info("filename does not exist? (%m)\n"); - return false; - } - if (!inbuf) - inbuf = (uint8_t *)malloc(INBUF_SIZE); /* 256 k */ - if (!inbuf) - { - hal_info("allocating input buffer failed (%m)\n"); - return false; - } - if (!pesbuf) - pesbuf = (uint8_t *)malloc(PESBUF_SIZE); /* 128 k */ - if (!pesbuf) - { - hal_info("allocating PES buffer failed (%m)\n"); - return false; - } - filelist_t file; - file.Name = std::string(filename); - file.Size = s.st_size; - if (file.Name.rfind(".ts") == file.Name.length() - 3 || - file.Name.rfind(".TS") == file.Name.length() - 3) - filetype = FILETYPE_TS; - else - { - if (file.Name.rfind(".vdr") == file.Name.length() - 4) - { - filetype = FILETYPE_VDR; - std::string::size_type p = file.Name.rfind("info.vdr"); - if (p == std::string::npos) - p = file.Name.rfind("index.vdr"); - if (p != std::string::npos) - { - file.Name.replace(p, std::string::npos, "001.vdr"); - hal_info("replaced filename with '%s'\n", file.Name.c_str()); - if (stat(file.Name.c_str(), &s)) - { - hal_info("filename does not exist? (%m)\n"); - return false; - } - file.Size = s.st_size; - } - } - else - filetype = FILETYPE_MPG; - vpid = 0x40; - } - - hal_info("detected (ok, guessed) filetype: %s\n", FILETYPE[filetype]); - - filelist.push_back(file); - filelist_auto_add(); - if (mf_open(0) < 0) - return false; - - pts_start = pts_end = pts_curr = -1; - pesbuf_pos = 0; - curr_pos = 0; - inbuf_pos = 0; - inbuf_sync = 0; - r = mf_getsize(); - - if (r > INBUF_SIZE) - { - if (mp_seekSync(r - INBUF_SIZE) < 0) - return false; - while(true) { - if (inbuf_read() <= 0) - break; // EOF - if (curr_pos >= r) //just to make sure... - break; - } - if (filetype == FILETYPE_TS) - for (r = (inbuf_pos / 188) * 188; r > 0; r -= 188) - { - pts_end = get_pts(inbuf + r, false, inbuf_pos - r); - if (pts_end > -1) - break; - } - else - pts_end = pts_curr; - } - else - pts_end = -1; /* unknown */ - - if (mp_seekSync(0) < 0) - return false; - - pesbuf_pos = 0; - inbuf_pos = 0; - inbuf_sync = 0; - while (inbuf_pos < INBUF_SIZE / 2 && inbuf_read() > 0) {}; - for (r = 0; r < inbuf_pos - 188; r += 188) - { - pts_start = get_pts(inbuf + r, false, inbuf_pos - r); - if (pts_start > -1) - break; - } - pts_curr = pts_start; - bytes_per_second = -1; - if (pts_end != -1 && pts_start > pts_end) /* PTS overflow during this file */ - pts_end += 0x200000000ULL; - int duration = (pts_end - pts_start) / 90000; - if (duration > 0) - bytes_per_second = mf_getsize() / duration; - hal_info("start: %lld end %lld duration %d bps %lld\n", pts_start, pts_end, duration, bytes_per_second); - /* yes, we start in pause mode... */ - playback_speed = 0; - if (pts_start == -1) - playstate = STATE_INIT; - else - playstate = STATE_PAUSE; - pthread_mutex_lock(&playback_ready_mutex); - if (pthread_create(&thread, 0, start_playthread, this) != 0) - hal_info("pthread_create failed\n"); - else - pthread_cond_wait(&playback_ready_cond, &playback_ready_mutex); - pthread_mutex_unlock(&playback_ready_mutex); - return true; -} - -static void *start_playthread(void *c) -{ - cPlayback *obj = (cPlayback *)c; - obj->playthread(); - return NULL; -} - -void cPlayback::playthread(void) -{ - thread_started = true; - int ret, towrite; - dvrfd = open(DVR, O_WRONLY); - if (dvrfd < 0) - { - hal_info("%s open tdpvr failed: %m\n", __FUNCTION__); - pthread_exit(NULL); - } - fcntl(dvrfd, F_SETFD, FD_CLOEXEC); - - pthread_cleanup_push(playthread_cleanup_handler, 0); - - ioctl(audioDemux->getFD(), DEMUX_SELECT_SOURCE, INPUT_FROM_PVR); - if (ac3) - audioDecoder->SetStreamType(AUDIO_FMT_DOLBY_DIGITAL); - else - { - if (streamtype == 1) /* mpeg 1 */ - audioDecoder->SetStreamType(AUDIO_FMT_MPG1); - else /* default */ - audioDecoder->SetStreamType(AUDIO_FMT_MPEG); - } - - audioDemux->pesFilter(apid); - videoDemux->pesFilter(vpid); - -// audioDemux->Start(); - videoDemux->Start(); - -// videoDecoder->setBlank(1); -// videoDecoder->Start(); -// audioDecoder->Start(); - /* everything is set up now, signal ::Start() that it can return */ - pthread_mutex_lock(&playback_ready_mutex); - pthread_cond_broadcast(&playback_ready_cond); - pthread_mutex_unlock(&playback_ready_mutex); - - while (playstate != STATE_STOP) - { - if (playstate == STATE_INIT) - { - /* hack for timeshift to determine start PTS */ - pthread_mutex_lock(&inbufpos_mutex); - ret = inbuf_read(); - pthread_mutex_unlock(&inbufpos_mutex); - if (ret < 0) - break; - usleep(100000); - if (pts_start == -1) - continue; - } - - if (playback_speed == 0) - { - playstate = STATE_PAUSE; - usleep(1); - continue; - } - pthread_mutex_lock(&inbufpos_mutex); - ret = inbuf_read(); - pthread_mutex_unlock(&inbufpos_mutex); - if (ret < 0) - break; - - /* autoselect PID for PLAYMODE_FILE */ - if (apid == 0 && astreams.size() > 0) - { - for (std::map::iterator aI = astreams.begin(); aI != astreams.end(); aI++) - { - if (!aI->second.ac3) - { - apid = aI->first; - hal_info("%s setting Audio pid to 0x%04hx\n", __FUNCTION__, apid); - SetAPid(apid, 0); - break; - } - } - } - - pthread_mutex_lock(&inbufpos_mutex); - towrite = inbuf_pos / 188 * 188; /* TODO: smaller chunks? */ - if (towrite == 0) - { - pthread_mutex_unlock(&inbufpos_mutex); - continue; - } - retry: - ret = write(dvrfd, inbuf, towrite); - if (ret < 0) - { - if (errno == EAGAIN && playstate != STATE_STOP) - goto retry; - hal_info("%s write dvr failed: %m\n", __FUNCTION__); - break; - } - memmove(inbuf, inbuf + ret, inbuf_pos - ret); - inbuf_pos -= ret; - pthread_mutex_unlock(&inbufpos_mutex); - } - - pthread_cleanup_pop(1); - pthread_exit(NULL); -} - -static void playthread_cleanup_handler(void *) -{ - hal_info_c("%s\n", __FUNCTION__); - ioctl(audioDemux->getFD(), DEMUX_SELECT_SOURCE, INPUT_FROM_CHANNEL0); - audioDemux->Stop(); - videoDemux->Stop(); - audioDecoder->Stop(); - videoDecoder->Stop(); - close(dvrfd); - dvrfd = -1; -} - -bool cPlayback::SetAPid(unsigned short pid, int _ac3) -{ - hal_info("%s pid: 0x%04hx ac3: %d\n", __FUNCTION__, pid, _ac3); - apid = pid; - ac3 = _ac3; - - audioDemux->Stop(); - audioDecoder->Stop(); - videoDemux->Stop(); - videoDecoder->Stop(false); - - if (ac3) - audioDecoder->SetStreamType(AUDIO_FMT_DOLBY_DIGITAL); - else - { - if (streamtype == 1) /* mpeg 1 */ - audioDecoder->SetStreamType(AUDIO_FMT_MPG1); - else /* default */ - audioDecoder->SetStreamType(AUDIO_FMT_MPEG); - } - audioDemux->pesFilter(apid); - - videoDemux->Start(); - audioDemux->Start(); - audioDecoder->Start(); - videoDecoder->Start(); - return true; -} - -bool cPlayback::SetSpeed(int speed) -{ - hal_info("%s speed = %d\n", __FUNCTION__, speed); - if (speed < 0) - speed = 1; /* fast rewind not yet implemented... */ - if (speed == 1 && playback_speed != 1) - { - if (playback_speed == 0) - { - videoDemux->Stop(); - videoDemux->Start(); - audioDemux->Start(); - } - else - { - audioDecoder->Stop(); - videoDecoder->Stop(); - } - audioDecoder->Start(); - videoDecoder->Start(); - playstate = STATE_PLAY; - /* cPlayback is a friend of cAudio and can use private methods */ - audioDecoder->do_mute(audioDecoder->Muted, false); - } - if (playback_speed == 1 && speed > 1) - { - audioDecoder->mute(false); - videoDecoder->FastForwardMode(); - } - playback_speed = speed; - if (playback_speed == 0) - { - audioDecoder->Stop(); - audioDemux->Stop(); - videoDecoder->Stop(false); - } - return true; -} - -bool cPlayback::GetSpeed(int &speed) const -{ - hal_debug("%s\n", __FUNCTION__); - speed = playback_speed; - return true; -} - -// in milliseconds -bool cPlayback::GetPosition(int &position, int &duration) -{ - int64_t tmppts; - hal_debug("%s\n", __FUNCTION__); - off_t currsize = mf_getsize(); - bool update = false; - /* handle a growing file, e.g. for timeshift. - this might be pretty expensive... */ - if (filetype == FILETYPE_TS && filelist.size() == 1) - { - off_t tmppos = currsize - PESBUF_SIZE; - if (currsize > last_size && (currsize - last_size) < 10485760 && - bytes_per_second > 0 && _pts_end > 0) - { - /* guess the current endpts... */ - tmppts = (currsize - last_size) * 90000 / bytes_per_second; - pts_end = _pts_end + tmppts; - } - else if (currsize != last_size && tmppos > 0) - { - pthread_mutex_lock(&currpos_mutex); - off_t oldpos = curr_pos; - ssize_t n, r; - int s; - mf_lseek(tmppos); - n = read(in_fd, pesbuf, PESBUF_SIZE); /* abuse the pesbuf... */ - s = sync_ts(pesbuf, n); - if (s >= 0) - { - n -= s; - for (r = (n / 188) * 188; r > 0; r -= 188) - { - tmppts = get_pts(pesbuf + r + s, false, n - r); - if (tmppts > -1) - { - hal_debug("n: %d s: %d endpts %lld size: %lld\n", n, s, tmppts, currsize); - pts_end = tmppts; - _pts_end = tmppts; - update = true; - /* file size has changed => update endpts */ - last_size = currsize; - break; - } - } - } - mf_lseek(oldpos); - pthread_mutex_unlock(&currpos_mutex); - } - } - if (pts_end != -1 && pts_start > pts_end) /* should trigger only once ;) */ - { - pts_end += 0x200000000ULL; - update = true; - } - - if (pts_curr != -1 && pts_curr < pts_start) - tmppts = pts_curr + 0x200000000ULL - pts_start; - else - tmppts = pts_curr - pts_start; - if (pts_end != -1 && pts_curr != -1) - { - position = tmppts / 90; - duration = (pts_end - pts_start) / 90; - if (update && duration >= 4000) - { - bytes_per_second = currsize / (duration / 1000); - hal_debug("%s: updated bps: %lld size: %lld duration %d\n", - __FUNCTION__, bytes_per_second, currsize, duration); - } - return true; - } - position = 0; - duration = 0; - return false; -} - -bool cPlayback::SetPosition(int position, bool absolute) -{ - hal_info("%s pos = %d abs = %d\n", __FUNCTION__, position, absolute); - int currpos, target, duration, oldspeed; - bool ret; - - if (absolute) - target = position; - else - { - GetPosition(currpos, duration); - target = currpos + position; - hal_info("current position %d target %d\n", currpos, target); - } - - oldspeed = playback_speed; -// if (oldspeed != 0) - SetSpeed(0); /* request pause */ - - while (playstate == STATE_PLAY) /* playthread did not acknowledge pause */ - usleep(1); - if (playstate == STATE_STOP) /* we did get stopped by someone else */ - return false; - - ret = (seek_to_pts(target * 90) > 0); - - if (oldspeed != 0) - { - SetSpeed(oldspeed); - /* avoid ugly artifacts */ - videoDecoder->Stop(); - videoDecoder->Start(); - } - return ret; -} - -void cPlayback::FindAllPids(uint16_t *apids, unsigned short *ac3flags, uint16_t *numpida, std::string *language) -{ - hal_info("%s\n", __FUNCTION__); - int i = 0; - for (std::map::iterator aI = astreams.begin(); aI != astreams.end(); aI++) - { - apids[i] = aI->first; - ac3flags[i] = aI->second.ac3 ? 1 : 0; - language[i] = aI->second.lang; - i++; - if (i > 10) /* REC_MAX_APIDS in vcrcontrol.h */ - break; - } - *numpida = i; -} - -/* it is unlikely that subtitle support will be implemented soon */ -void cPlayback::FindAllSubs(uint16_t *, unsigned short *, uint16_t *num, std::string *) -{ - *num = 0; -} - -bool cPlayback::SelectSubtitles(int) -{ - return false; -} - -/* DVD support is also unlikely... */ -void cPlayback::GetChapters(std::vector &positions, std::vector &titles) -{ - positions.clear(); - titles.clear(); -} - -off_t cPlayback::seek_to_pts(int64_t pts) -{ - off_t newpos = curr_pos; - int64_t tmppts, ptsdiff; - int count = 0; - if (pts_start < 0 || pts_end < 0 || bytes_per_second < 0) - { - hal_info("%s pts_start (%lld) or pts_end (%lld) or bytes_per_second (%lld) not initialized\n", - __FUNCTION__, pts_start, pts_end, bytes_per_second); - return -1; - } - /* sanity check: buffer is without locking, so we must only seek while in pause mode */ - if (playstate != STATE_PAUSE) - { - hal_info("%s playstate (%d) != STATE_PAUSE, not seeking\n", __FUNCTION__, playstate); - return -1; - } - - /* tmppts is normalized current pts */ - if (pts_curr < pts_start) - tmppts = pts_curr + 0x200000000ULL - pts_start; - else - tmppts = pts_curr - pts_start; - while (abs(pts - tmppts) > 90000LL && count < 10) - { - count++; - ptsdiff = pts - tmppts; - newpos += ptsdiff * bytes_per_second / 90000; - hal_info("%s try #%d seek from %lldms to %lldms dt %lldms pos %lldk newpos %lldk kB/s %lld\n", - __FUNCTION__, count, tmppts / 90, pts / 90, ptsdiff / 90, curr_pos / 1024, newpos / 1024, bytes_per_second / 1024); - if (newpos < 0) - newpos = 0; - newpos = mp_seekSync(newpos); - if (newpos < 0) - return newpos; - pthread_mutex_lock(&inbufpos_mutex); - inbuf_pos = 0; - inbuf_sync = 0; - while (inbuf_pos < INBUF_SIZE * 8 / 10) { - if (inbuf_read() <= 0) - break; // EOF - } - pthread_mutex_unlock(&inbufpos_mutex); - if (pts_curr < pts_start) - tmppts = pts_curr + 0x200000000ULL - pts_start; - else - tmppts = pts_curr - pts_start; - } - hal_info("%s end after %d tries, ptsdiff now %lld sec\n", __FUNCTION__, count, (pts - tmppts) / 90000); - return newpos; -} - -bool cPlayback::filelist_auto_add() -{ - if (filelist.size() != 1) - return false; - - const char *filename = filelist[0].Name.c_str(); - const char *ext; - ext = strrchr(filename, '.'); // FOO-xxx-2007-12-31.001.ts <- the dot before "ts" - // 001.vdr <- the dot before "vdr" - // check if there is something to do... - if (! ext) - return false; - if (!((ext - 7 >= filename && !strcmp(ext, ".ts") && *(ext - 4) == '.') || - (ext - 4 >= filename && !strcmp(ext, ".vdr")))) - return false; - - int num = 0; - struct stat s; - size_t numpos = strlen(filename) - strlen(ext) - 3; - sscanf(filename + numpos, "%d", &num); - do { - num++; - char nextfile[strlen(filename) + 1]; /* todo: use fixed buffer? */ - memcpy(nextfile, filename, numpos); - sprintf(nextfile + numpos, "%03d%s", num, ext); - if (stat(nextfile, &s)) - break; // file does not exist - filelist_t file; - file.Name = std::string(nextfile); - file.Size = s.st_size; - hal_info("%s auto-adding '%s' to playlist\n", __FUNCTION__, nextfile); - filelist.push_back(file); - } while (true && num < 999); - - return (filelist.size() > 1); -} - -/* the mf_* functions are wrappers for multiple-file I/O */ -int cPlayback::mf_open(int fileno) -{ - if (filelist.empty()) - return -1; - - if (fileno >= (int)filelist.size()) - return -1; - - mf_close(); - - in_fd = open(filelist[fileno].Name.c_str(), O_RDONLY); - fcntl(in_fd, F_SETFD, FD_CLOEXEC); - if (in_fd != -1) - curr_fileno = fileno; - - return in_fd; -} - -int cPlayback::mf_close(void) -{ - int ret = 0; - hal_info("%s in_fd = %d curr_fileno = %d\n", __FUNCTION__, in_fd, curr_fileno); - if (in_fd != -1) - ret = close(in_fd); - in_fd = curr_fileno = -1; - - return ret; -} - -off_t cPlayback::mf_getsize(void) -{ - off_t ret = 0; - if (filelist.size() == 1 && in_fd != -1) - { - /* for timeshift, we need to deal with a growing file... */ - struct stat st; - if (fstat(in_fd, &st) == 0) - return st.st_size; - /* else, fallback to filelist.size() */ - } - for (unsigned int i = 0; i < filelist.size(); i++) - ret += filelist[i].Size; - return ret; -} - -off_t cPlayback::mf_lseek(off_t pos) -{ - off_t offset = 0, lpos = pos, ret; - unsigned int fileno; - /* this is basically needed for timeshifting - to allow - growing files to be handled... */ - if (filelist.size() == 1 && filetype == FILETYPE_TS) - { - if (lpos > mf_getsize()) - return -2; - fileno = 0; - } - else - { - for (fileno = 0; fileno < filelist.size(); fileno++) - { - if (lpos < filelist[fileno].Size) - break; - offset += filelist[fileno].Size; - lpos -= filelist[fileno].Size; - } - if (fileno == filelist.size()) - return -2; // EOF - } - - if ((int)fileno != curr_fileno) - { - hal_info("%s old fileno: %d new fileno: %d, offset: %lld\n", __FUNCTION__, curr_fileno, fileno, (long long)lpos); - in_fd = mf_open(fileno); - if (in_fd < 0) - { - hal_info("cannot open file %d:%s (%m)\n", fileno, filelist[fileno].Name.c_str()); - return -1; - } - } - - ret = lseek(in_fd, lpos, SEEK_SET); - if (ret < 0) - return ret; - - curr_pos = offset + ret; - return curr_pos; -} - -/* gets the PTS at a specific file position from a PES - ATTENTION! resets buf! */ -int64_t cPlayback::get_PES_PTS(uint8_t *buf, int len, bool last) -{ - int64_t pts = -1; - int off, plen; - uint8_t *p; - - off = mp_syncPES(buf, len); - - if (off < 0) - return off; - - p = buf + off; - while (off < len - 14 && (pts == -1 || last)) - { - plen = ((p[4] << 8) | p[5]) + 6; - - switch(p[3]) - { - int64_t tmppts; - case 0xe0 ... 0xef: // video! - tmppts = get_pts(p, true, len - off); - if (tmppts >= 0) - pts = tmppts; - break; - case 0xbb: - case 0xbe: - case 0xbf: - case 0xf0 ... 0xf3: - case 0xff: - case 0xc0 ... 0xcf: - case 0xd0 ... 0xdf: - break; - case 0xb9: - case 0xba: - case 0xbc: - default: - plen = 1; - break; - } - p += plen; - off += plen; - } - return pts; -} - -/* needs to be called with inbufpos_mutex locked! */ -ssize_t cPlayback::inbuf_read() -{ - if (filetype == FILETYPE_UNKNOWN) - return -1; - if (filetype == FILETYPE_TS) - return read_ts(); - /* FILETYPE_MPG or FILETYPE_VDR */ - return read_mpeg(); -} - -ssize_t cPlayback::read_ts() -{ - ssize_t toread, ret = 0, sync, off; - toread = INBUF_SIZE - inbuf_pos; - bool retry = true; - uint8_t *buf; - /* fprintf(stderr, "%s:%d curr_pos %lld, inbuf_pos: %ld, toread: %ld\n", - __FUNCTION__, __LINE__, (long long)curr_pos, (long)inbuf_pos, (long)toread); */ - - if (playback_speed > 1) - { - sync = 0; - ssize_t tmpread = PESBUF_SIZE / 188 * 188; - int n, skipped = 0; - bool skip = false; - bool eof = true; - pthread_mutex_lock(&currpos_mutex); - while (toread > 0) - { - ssize_t done = 0; - while (done < tmpread) - { - ret = read(in_fd, pesbuf, tmpread - done); - if (ret == 0 && retry) /* EOF */ - { - mf_lseek(curr_pos); - retry = false; - continue; - } - if (ret < 0) - { - hal_info("%s failed1: %m\n", __FUNCTION__); - pthread_mutex_unlock(&currpos_mutex); - return ret; - } - if (ret == 0 && eof) - goto out; - eof = false; - done += ret; - curr_pos += ret; - } - sync = sync_ts(pesbuf, ret); - if (sync != 0) - { - hal_info("%s out of sync: %d\n", __FUNCTION__, sync); - if (sync < 0) - { - pthread_mutex_unlock(&currpos_mutex); - return -1; - } - memmove(pesbuf, pesbuf + sync, ret - sync); - if (pesbuf[0] != 0x47) - hal_info("%s:%d??????????????????????????????\n", __FUNCTION__, __LINE__); - } - for (n = 0; n < done / 188 * 188; n += 188) - { - buf = pesbuf + n; - if (buf[1] & 0x40) // PUSI - { - /* only video packets... */ - int of = 4; - if (buf[3] & 0x20) // adaptation field - of += buf[4] + 1; - if ((buf[of + 3] & 0xF0) == 0xE0 && // Video stream - buf[of + 2] == 0x01 && buf[of + 1] == 0x00 && buf[of] == 0x00) // PES - { - skip = true; - skipped++; - if (skipped >= playback_speed) - { - skipped = 0; - skip = false; - } - } - } - if (! skip) - { - memcpy(inbuf + inbuf_pos, buf, 188); - inbuf_pos += 188; - toread -= 188; - if (toread <= 0) - { - /* the output buffer is full, discard the input :-( */ - if (done - n > 0) - { - hal_debug("%s not done: %d, resetting filepos\n", - __FUNCTION__, done - n); - mf_lseek(curr_pos - (done - n)); - } - break; - } - } - } - } - out: - pthread_mutex_unlock(&currpos_mutex); - if (eof) - return 0; - } - else - { - pthread_mutex_lock(&currpos_mutex); - while(true) - { - ret = read(in_fd, inbuf + inbuf_pos, toread); - if (ret == 0 && retry) /* EOF */ - { - mf_lseek(curr_pos); - retry = false; - continue; - } - break; - } - if (ret <= 0) - { - pthread_mutex_unlock(&currpos_mutex); - if (ret < 0) - hal_info("%s failed2: %m\n", __FUNCTION__); - return ret; - } - inbuf_pos += ret; - curr_pos += ret; - pthread_mutex_unlock(&currpos_mutex); - - sync = sync_ts(inbuf + inbuf_sync, INBUF_SIZE - inbuf_sync); - if (sync < 0) - { - hal_info("%s cannot sync\n", __FUNCTION__); - return ret; - } - inbuf_sync += sync; - } - /* check for A/V PIDs */ - uint16_t pid; - int i; - int64_t pts; - //fprintf(stderr, "inbuf_pos: %ld - sync: %ld, inbuf_syc: %ld\n", (long)inbuf_pos, (long)sync, (long)inbuf_sync); - int synccnt = 0; - for (i = 0; i < inbuf_pos - inbuf_sync - 13;) { - buf = inbuf + inbuf_sync + i; - if (*buf != 0x47) - { - synccnt++; - i++; - continue; - } - if (synccnt) - hal_info("%s TS went out of sync %d\n", __FUNCTION__, synccnt); - synccnt = 0; - if (!(buf[1] & 0x40)) /* PUSI */ - { - i += 188; - continue; - } - off = 0; - if (buf[3] & 0x20) /* adaptation field? */ - off = buf[4] + 1; - pid = get_pid(buf + 1); - /* PES signature is at buf + 4, streamtype is after 00 00 01 */ - switch (buf[4 + 3 + off]) - { - case 0xe0 ... 0xef: /* video stream */ - if (vpid == 0) - vpid = pid; - pts = get_pts(buf + 4 + off, true, inbuf_pos - inbuf_sync - i - off - 4); - if (pts < 0) - break; - pts_curr = pts; - if (pts_start < 0) - { - hal_info("%s updating pts_start to %lld ", __FUNCTION__, pts); - pts_start = pts; - if (pts_end > -1) - { - if (pts_end < pts_start) - { - pts_end += 0x200000000ULL; - fprintf(stderr, "pts_end to %lld ", pts_end); - } - int duration = (pts_end - pts_start) / 90000; - if (duration > 0) - { - bytes_per_second = (mf_getsize() - curr_pos) / duration; - fprintf(stderr, "bytes_per_second to %lldk duration to %ds at %lldk", - bytes_per_second / 1024, duration, curr_pos / 1024); - } - } - fprintf(stderr, "\n"); - } - break; - case 0xbd: /* private stream 1 - ac3 */ - case 0xc0 ... 0xdf: /* audio stream */ - if (astreams.find(pid) != astreams.end()) - break; - AStream tmp; - if (buf[7 + off] == 0xbd) - { - if (buf[12 + off] == 0x24) /* 0x24 == TTX */ - break; - tmp.ac3 = true; - } - else - tmp.ac3 = false; - tmp.lang = ""; - astreams.insert(std::make_pair(pid, tmp)); - hal_info("%s found apid #%d 0x%04hx ac3:%d\n", __func__, astreams.size(), pid, tmp.ac3); - break; - } - i += 188; - } - - // fprintf(stderr, "%s:%d ret %ld\n", __FUNCTION__, __LINE__, (long long)ret); - return ret; -} - -ssize_t cPlayback::read_mpeg() -{ - ssize_t toread, ret, sync; - //toread = PESBUF_SIZE - pesbuf_pos; - /* experiments found, that 80kB is the best buffer size, otherwise a/v sync seems - to suffer and / or audio stutters */ - toread = 80 * 1024 - pesbuf_pos; - bool retry = true; - - if (INBUF_SIZE - inbuf_pos < toread) - { - hal_info("%s inbuf full, setting toread to %d (old: %zd)\n", __FUNCTION__, INBUF_SIZE - inbuf_pos, toread); - toread = INBUF_SIZE - inbuf_pos; - } - pthread_mutex_lock(&currpos_mutex); - while(true) - { - ret = read(in_fd, pesbuf + pesbuf_pos, toread); - if (ret == 0 && retry) /* EOF */ - { - mf_lseek(curr_pos); - retry = false; - continue; - } - break; - } - if (ret < 0) - { - pthread_mutex_unlock(&currpos_mutex); - hal_info("%s failed: %m, pesbuf_pos: %zd, toread: %zd\n", __FUNCTION__, pesbuf_pos, toread); - return ret; - } - pesbuf_pos += ret; - curr_pos += ret; - pthread_mutex_unlock(&currpos_mutex); - - int count = 0; - uint16_t pid = 0; - bool resync = true; - while (count < pesbuf_pos - 10) - { - if (resync) - { - sync = mp_syncPES(pesbuf + count, pesbuf_pos - count - 10); - if (sync < 0) - { - if (pesbuf_pos - count - 10 > 4) - hal_info("%s cannot sync (count=%d, pesbuf_pos=%zd)\n", - __FUNCTION__, count, pesbuf_pos); - break; - } - if (sync) - hal_info("%s needed sync %zd\n", __FUNCTION__, sync); - count += sync; - } - uint8_t *ppes = pesbuf + count; - int av = 0; // 1 = video, 2 = audio - int64_t pts; - switch(ppes[3]) - { - case 0xba: //pack header; - // fprintf(stderr, "pack start code, 0x%02x\n", ppes[4]); - if ((ppes[4] & 0xf0) == 0x20) /* mpeg 1 */ - { - streamtype = 1; /* for audio setup */ - count += 12; - } - else if ((ppes[4] & 0xc0) == 0x40) /* mpeg 2 */ - { - streamtype = 0; - count += 14; /* correct: 14 + (ppes[13] & 0x07) */ - } - else - { - hal_info("%s weird pack header: 0x%2x\n", __FUNCTION__, ppes[4]); - count++; - } - resync = true; - continue; - break; - case 0xbd: // AC3 - { - int off = ppes[8] + 8 + 1; // ppes[8] is often 0 - if (count + off >= pesbuf_pos) - break; - uint16_t subid = ppes[off]; - // if (offset == 0x24 && subid == 0x10 ) // TTX? - if (subid < 0x80 || subid > 0x87) - break; - hal_debug("AC3: ofs 0x%02x subid 0x%02x\n", off, subid); - //subid -= 0x60; // normalize to 32...39 (hex 0x20..0x27) - - if (astreams.find(subid) == astreams.end()) - { - AStream tmp; - tmp.ac3 = true; - tmp.lang = ""; - astreams.insert(std::make_pair(subid, tmp)); - hal_info("%s found aid: %02x\n", __FUNCTION__, subid); - } - pid = subid; - av = 2; - break; - } - case 0xbb: - case 0xbe: - case 0xbf: - case 0xf0 ... 0xf3: - case 0xff: - //skip = (ppes[4] << 8 | ppes[5]) + 6; - //DBG("0x%02x header, skip = %d\n", ppes[3], skip); - break; - case 0xc0 ... 0xcf: - case 0xd0 ... 0xdf: - { - // fprintf(stderr, "audio stream 0x%02x\n", ppes[3]); - uint16_t id = ppes[3]; - if (astreams.find(id) == astreams.end()) - { - AStream tmp; - tmp.ac3 = false; - tmp.lang = ""; - astreams.insert(std::make_pair(id, tmp)); - hal_info("%s found aid: %02x\n", __FUNCTION__, id); - } - pid = id; - av = 2; - break; - } - case 0xe0 ... 0xef: - // fprintf(stderr, "video stream 0x%02x, %02x %02x \n", ppes[3], ppes[4], ppes[5]); - pid = 0x40; - av = 1; - pts = get_pts(ppes, true, pesbuf_pos - count); - if (pts < 0) - break; - pts_curr = pts; - if (pts_start < 0) - pts_start = pts; - break; - case 0xb9: - case 0xbc: - hal_debug("%s:%d %s\n", __FUNCTION__, __LINE__, - (ppes[3] == 0xb9) ? "program_end_code" : "program_stream_map"); - //resync = true; - // fallthrough. TODO: implement properly. - default: - //if (! resync) - // DBG("Unknown stream id: 0x%X.\n", ppes[3]); - count++; - resync = true; - continue; - break; - } - - int pesPacketLen = ((ppes[4] << 8) | ppes[5]) + 6; - if (count + pesPacketLen >= pesbuf_pos) - { - hal_debug("buffer len: %ld, pesPacketLen: %d :-(\n", pesbuf_pos - count, pesPacketLen); - break; - } - - int tsPacksCount = pesPacketLen / 184; - if ((tsPacksCount + 1) * 188 > INBUF_SIZE - inbuf_pos) - { - hal_info("not enough size in inbuf (needed %d, got %d)\n", (tsPacksCount + 1) * 188, INBUF_SIZE - inbuf_pos); - break; - } - - if (av) - { - int rest = pesPacketLen % 184; - - // divide PES packet into small TS packets - uint8_t pusi = 0x40; - int j; - uint8_t *ts = inbuf + inbuf_pos; - for (j = 0; j < tsPacksCount; j++) - { - ts[0] = 0x47; // SYNC Byte - ts[1] = pusi; // Set PUSI if first packet - ts[2] = pid; // PID (low) - ts[3] = 0x10 | (cc[pid] & 0x0F); // No adaptation field, payload only, continuity counter - cc[pid]++; - memcpy(ts + 4, ppes + j * 184, 184); - pusi = 0x00; // clear PUSI - ts += 188; - inbuf_pos += 188; - } - - if (rest > 0) - { - ts[0] = 0x47; // SYNC Byte - ts[1] = pusi; // Set PUSI or - ts[2] = pid; // PID (low) - ts[3] = 0x30 | (cc[pid] & 0x0F); // adaptation field, payload, continuity counter - cc[pid]++; - ts[4] = 183 - rest; - if (ts[4] > 0) - { - ts[5] = 0x00; - memset(ts + 6, 0xFF, ts[4] - 1); - } - memcpy(ts + 188 - rest, ppes + j * 184, rest); - inbuf_pos += 188; - } - } //if (av) - - count += pesPacketLen; - } - memmove(pesbuf, pesbuf + count, pesbuf_pos - count); - pesbuf_pos -= count; - return ret; -} - -//== seek to pos with sync to next proper TS packet == -//== returns offset to start of TS packet or actual == -//== pos on failure. == -//==================================================== -off_t cPlayback::mp_seekSync(off_t pos) -{ - off_t npos = pos; - off_t ret; - uint8_t pkt[1024]; - - pthread_mutex_lock(&currpos_mutex); - ret = mf_lseek(npos); - if (ret < 0) - hal_info("%s:%d lseek ret < 0 (%m)\n", __FUNCTION__, __LINE__); - - if (filetype != FILETYPE_TS) - { - int offset = 0; - int s; - ssize_t r; - bool retry = false; - while (true) - { - r = read(in_fd, &pkt[offset], 1024 - offset); - if (r < 0) - { - hal_info("%s read failed: %m\n", __FUNCTION__); - break; - } - if (r == 0) // EOF? - { - if (retry) - break; - if (mf_lseek(npos) < 0) /* next file in list? */ - { - hal_info("%s:%d lseek ret < 0 (%m)\n", __FUNCTION__, __LINE__); - break; - } - retry = true; - continue; - } - s = mp_syncPES(pkt, r + offset, true); - if (s < 0) - { - /* if the last 3 bytes of the buffer were 00 00 01, then - mp_sync_PES would not find it. So keep them and check - again in the next iteration */ - memmove(pkt, &pkt[r + offset - 3], 3); - npos += r; - offset = 3; - } - else - { - npos += s; - hal_info("%s sync after %lld\n", __FUNCTION__, npos - pos); - ret = mf_lseek(npos); - pthread_mutex_unlock(&currpos_mutex); - if (ret < 0) - hal_info("%s:%d lseek ret < 0 (%m)\n", __FUNCTION__, __LINE__); - return ret; - } - if (npos > (pos + 0x20000)) /* 128k enough? */ - break; - } - hal_info("%s could not sync to PES offset: %d r: %zd\n", __FUNCTION__, offset, r); - ret = mf_lseek(pos); - pthread_mutex_unlock(&currpos_mutex); - return ret; - } - - /* TODO: use bigger buffer here, too and handle EOF / next splitfile */ - while (read(in_fd, pkt, 1) > 0) - { - //-- check every byte until sync word reached -- - npos++; - if (*pkt == 0x47) - { - //-- if found double check for next sync word -- - if (read(in_fd, pkt, 188) == 188) - { - if(pkt[188-1] == 0x47) - { - ret = mf_lseek(npos - 1); // assume sync ok - pthread_mutex_unlock(&currpos_mutex); - if (ret < 0) - hal_info("%s:%d lseek ret < 0 (%m)\n", __FUNCTION__, __LINE__); - return ret; - } - else - { - ret = mf_lseek(npos); // oops, next pkt doesn't start with sync - if (ret < 0) - hal_info("%s:%d lseek ret < 0 (%m)\n", __FUNCTION__, __LINE__); - } - } - } - - //-- check probe limits -- - if (npos > (pos + 100 * 188)) - break; - } - - //-- on error stay on actual position -- - ret = mf_lseek(pos); - pthread_mutex_unlock(&currpos_mutex); - return ret; -} - -static int sync_ts(uint8_t *p, int len) -{ - int count; - if (len < 189) - return -1; - - count = 0; - while (*p != 0x47 || *(p + 188) != 0x47) - { - count++; - p++; - if (count + 188 > len) - return -1; - } - return count; -} - -/* get the pts value from a TS or PES packet - pes == true selects PES mode. */ -int64_t cPlayback::get_pts(uint8_t *p, bool pes, int bufsize) -{ - const uint8_t *end = p + bufsize; /* check for overflow */ - if (bufsize < 14) - return -1; - if (!pes) - { - if (p[0] != 0x47) - return -1; - if (!(p[1] & 0x40)) - return -1; - if (get_pid(p + 1) != vpid) - return -1; - if (!(p[3] & 0x10)) - return -1; - - if (p[3] & 0x20) - p += p[4] + 4 + 1; - else - p += 4; - - if (p + 13 > end) - return -1; - /* p is now pointing at the PES header. hopefully */ - if (p[0] || p[1] || (p[2] != 1)) - return -1; - } - - if ((p[6] & 0xC0) != 0x80) // MPEG1 - { - p += 6; - while (*p == 0xff) - { - p++; - if (p > end) - return -1; - } - if ((*p & 0xc0) == 0x40) - p += 2; - p -= 9; /* so that the p[9]...p[13] matches the below */ - if (p + 13 > end) - return -1; - } - else - { - /* MPEG2 */ - if ((p[7] & 0x80) == 0) // packets with both pts, don't care for dts - // if ((p[7] & 0xC0) != 0x80) // packets with only pts - // if ((p[7] & 0xC0) != 0xC0) // packets with pts and dts - return -1; - if (p[8] < 5) - return -1; - } - - if (!(p[9] & 0x20)) - return -1; - - int64_t pts = - ((p[ 9] & 0x0EULL) << 29) | - ((p[10] & 0xFFULL) << 22) | - ((p[11] & 0xFEULL) << 14) | - ((p[12] & 0xFFULL) << 7) | - ((p[13] & 0xFEULL) >> 1); - - //int msec = pts / 90; - //INFO("time: %02d:%02d:%02d\n", msec / 3600000, (msec / 60000) % 60, (msec / 1000) % 60); - return pts; -} - -/* returns: 0 == was already synchronous, > 0 == is now synchronous, -1 == could not sync */ -static int mp_syncPES(uint8_t *buf, int len, bool quiet) -{ - int ret = 0; - while (ret < len - 4) - { - if (buf[ret + 2] != 0x01) - { - ret++; - continue; - } - if (buf[ret + 1] != 0x00) - { - ret += 2; - continue; - } - if (buf[ret] != 0x00) - { - ret += 3; - continue; - } - /* all stream IDs are > 0x80 */ - if ((buf[ret + 3] & 0x80) != 0x80) - { - /* we already checked for 00 00 01, if the stream ID - is not valid, we can skip those 3 bytes */ - ret += 3; - continue; - } - return ret; - } - - if (!quiet && len > 5) /* only warn if enough space was available... */ - hal_info_c("%s No valid PES signature found. %d Bytes deleted.\n", __FUNCTION__, ret); - return -1; -} - -static inline uint16_t get_pid(uint8_t *buf) -{ - return (*buf & 0x1f) << 8 | *(buf + 1); -} - diff --git a/libtriple/playback_td.h b/libtriple/playback_td.h deleted file mode 100644 index cd534b6..0000000 --- a/libtriple/playback_td.h +++ /dev/null @@ -1,129 +0,0 @@ -#ifndef __PLAYBACK_TD_H__ -#define __PLAYBACK_TD_H__ - -#include -#include -#include -#include - -/* 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; /* 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 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 &positions, std::vector &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__ diff --git a/libtriple/record_td.cpp b/libtriple/record_td.cpp deleted file mode 100644 index 119d762..0000000 --- a/libtriple/record_td.cpp +++ /dev/null @@ -1,275 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#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 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::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::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 pids; - hal_info("%s: \n", __func__); - if (!dmx) { - hal_info("%s: DMX = NULL\n", __func__); - return false; - } - pids = dmx->pesfds; - for (std::vector::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; -} diff --git a/libtriple/record_td.h b/libtriple/record_td.h deleted file mode 100644 index f77bdf9..0000000 --- a/libtriple/record_td.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef __RECORD_TD_H__ -#define __RECORD_TD_H__ - -#include -#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__ diff --git a/libtriple/td-compat/td-audio-compat.h b/libtriple/td-compat/td-audio-compat.h deleted file mode 100644 index 3e0b4a7..0000000 --- a/libtriple/td-compat/td-audio-compat.h +++ /dev/null @@ -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 -// 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__ */ diff --git a/libtriple/td-compat/td-demux-compat.h b/libtriple/td-compat/td-demux-compat.h deleted file mode 100644 index 8feacfe..0000000 --- a/libtriple/td-compat/td-demux-compat.h +++ /dev/null @@ -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 -#include -// 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__ */ diff --git a/libtriple/td-compat/td-frontend-compat.h b/libtriple/td-compat/td-frontend-compat.h deleted file mode 100644 index 46781ce..0000000 --- a/libtriple/td-compat/td-frontend-compat.h +++ /dev/null @@ -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 -#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__ */ diff --git a/libtriple/td-compat/td-value-compat.h b/libtriple/td-compat/td-value-compat.h deleted file mode 100644 index f7bb952..0000000 --- a/libtriple/td-compat/td-value-compat.h +++ /dev/null @@ -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 -#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_ */ diff --git a/libtriple/td-compat/td-video-compat.h b/libtriple/td-compat/td-video-compat.h deleted file mode 100644 index 137a346..0000000 --- a/libtriple/td-compat/td-video-compat.h +++ /dev/null @@ -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 -// 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__ */ diff --git a/libtriple/video_td.cpp b/libtriple/video_td.cpp deleted file mode 100644 index 72e7e79..0000000 --- a/libtriple/video_td.cpp +++ /dev/null @@ -1,1107 +0,0 @@ -/* - * (C) 2002-2003 Andreas Oberritter - * (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 . - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include -#include -#include -#include "video_td.h" -#include -#define VIDEO_DEVICE "/dev/" DEVICE_NAME_VIDEO -#include "hal_debug.h" -#define hal_debug(args...) _hal_debug(HAL_DEBUG_VIDEO, this, args) -#define hal_info(args...) _hal_info(HAL_DEBUG_VIDEO, this, args) - -#define fop(cmd, args...) ({ \ - int _r; \ - if (fd >= 0) { \ - if ((_r = ::cmd(fd, args)) < 0) \ - hal_info(#cmd"(fd, "#args")\n"); \ - else \ - hal_debug(#cmd"(fd, "#args")\n");\ - } \ - else { _r = fd; } \ - _r; \ -}) - -cVideo * videoDecoder = NULL; -int system_rev = 0; - -#if 0 -/* this would be necessary for the DirectFB implementation of ShowPicture */ -#include -#include -extern IDirectFB *dfb; -extern IDirectFBSurface *dfbdest; -#endif - -extern struct Ssettings settings; -static pthread_mutex_t stillp_mutex = PTHREAD_MUTEX_INITIALIZER; - -/* debugging hacks */ -static bool noscart = false; - -cVideo::cVideo(int, void *, void *, unsigned int) -{ - hal_debug("%s\n", __FUNCTION__); - if ((fd = open(VIDEO_DEVICE, O_RDWR)) < 0) - hal_info("%s cannot open %s: %m\n", __FUNCTION__, VIDEO_DEVICE); - fcntl(fd, F_SETFD, FD_CLOEXEC); - - playstate = VIDEO_STOPPED; - croppingMode = VID_DISPMODE_NORM; - outputformat = VID_OUTFMT_RGBC_SVIDEO; - scartvoltage = -1; - z[0] = 100; - z[1] = 100; - zoomvalue = &z[0]; - const char *blanknames[2] = { "/share/tuxbox/blank_576.mpg", "/share/tuxbox/blank_480.mpg" }; - int blankfd; - struct stat st; - - for (int i = 0; i < 2; i++) - { - blank_data[i] = NULL; /* initialize */ - blank_size[i] = 0; - blankfd = open(blanknames[i], O_RDONLY); - if (blankfd < 0) - { - hal_info("%s cannot open %s: %m", __FUNCTION__, blanknames[i]); - continue; - } - if (fstat(blankfd, &st) != -1 && st.st_size > 0) - { - blank_size[i] = st.st_size; - blank_data[i] = malloc(blank_size[i]); - if (! blank_data[i]) - hal_info("%s malloc failed (%m)\n", __FUNCTION__); - else if (read(blankfd, blank_data[i], blank_size[i]) != blank_size[i]) - { - hal_info("%s short read (%m)\n", __FUNCTION__); - free(blank_data[i]); /* don't leak... */ - blank_data[i] = NULL; - } - else - { /* set framerate to 24fps... see getBlank() */ - ((char *)blank_data[i])[7] &= 0xF0; - ((char *)blank_data[i])[7] += 2; - } - } - close(blankfd); - } - video_standby = 0; - noscart = (getenv("TRIPLE_NOSCART") != NULL); - if (noscart) - hal_info("%s TRIPLE_NOSCART variable prevents SCART switching\n", __FUNCTION__); -} - -cVideo::~cVideo(void) -{ - playstate = VIDEO_STOPPED; - for (int i = 0; i < 2; i++) - { - if (blank_data[i]) - free(blank_data[i]); - blank_data[i] = NULL; - } - /* disable DACs and SCART voltage */ - Standby(true); - if (fd >= 0) - close(fd); -} - -int cVideo::setAspectRatio(int aspect, int mode) -{ - static int _mode = -1; - static int _aspect = -1; - vidDispSize_t dsize = VID_DISPSIZE_UNKNOWN; - vidDispMode_t dmode = VID_DISPMODE_NORM; - /* 1 = 4:3, 3 = 16:9, 4 = 2.21:1, 0 = unknown */ - int v_ar = getAspectRatio(); - - if (aspect != -1) - _aspect = aspect; - if (mode != -1) - _mode = mode; - hal_info("%s(%d, %d)_(%d, %d) v_ar %d\n", __FUNCTION__, aspect, mode, _aspect, _mode, v_ar); - - /* values are hardcoded in neutrino_menue.cpp, "2" is 14:9 -> not used */ - if (_aspect != -1) - { - switch(_aspect) - { - case 1: - dsize = VID_DISPSIZE_4x3; - scartvoltage = 12; - break; - case 3: - dsize = VID_DISPSIZE_16x9; - scartvoltage = 6; - break; - default: - break; - } - } - if (_mode != -1) - { - int zoom = 100 * 16 / 14; /* 16:9 vs 14:9 */ - switch(_mode) - { - case DISPLAY_AR_MODE_NONE: - if (v_ar < 3) - dsize = VID_DISPSIZE_4x3; - else - dsize = VID_DISPSIZE_16x9; - break; - case DISPLAY_AR_MODE_LETTERBOX: - dmode = VID_DISPMODE_LETTERBOX; - break; - case DISPLAY_AR_MODE_PANSCAN: - zoom = 100 * 5 / 4; - case DISPLAY_AR_MODE_PANSCAN2: - if ((v_ar < 3 && _aspect == 3) || (v_ar >= 3 && _aspect == 1)) - { - /* unfortunately, this partly reimplements the setZoom code... */ - dsize = VID_DISPSIZE_UNKNOWN; - dmode = VID_DISPMODE_SCALE; - SCALEINFO s; - memset(&s, 0, sizeof(s)); - if (v_ar < 3) { /* 4:3 */ - s.src.hori_size = 720; - s.src.vert_size = 2 * 576 - 576 * zoom / 100; - s.des.hori_size = zoom * 720 * 3/4 / 100; - s.des.vert_size = 576; - } else { - s.src.hori_size = 2 * 720 - 720 * zoom / 100; - s.src.vert_size = 576; - s.des.hori_size = 720; - s.des.vert_size = zoom * 576 * 3/4 / 100; - } - s.des.vert_off = (576 - s.des.vert_size) / 2; - s.des.hori_off = (720 - s.des.hori_size) / 2; - hal_debug("PANSCAN2: %d%% src: %d:%d:%d:%d dst: %d:%d:%d:%d\n", zoom, - s.src.hori_off,s.src.vert_off,s.src.hori_size,s.src.vert_size, - s.des.hori_off,s.des.vert_off,s.des.hori_size,s.des.vert_size); - fop(ioctl, MPEG_VID_SCALE_ON); - fop(ioctl, MPEG_VID_SET_SCALE_POS, &s); - } - default: - break; - } - if (dmode != VID_DISPMODE_SCALE) - fop(ioctl, MPEG_VID_SCALE_OFF); - setCroppingMode(dmode); - } - const char *ds[] = { "4x3", "16x9", "2.21", "unknown" }; - const char *d; - if (dsize >=0 && dsize < 4) - d = ds[dsize]; - else - d = "invalid!"; - hal_debug("%s dispsize(%d) (%s)\n", __FUNCTION__, dsize, d); - fop(ioctl, MPEG_VID_SET_DISPSIZE, dsize); - - int avsfd = open("/dev/stb/tdsystem", O_RDONLY); - if (avsfd < 0) - { - perror("open tdsystem"); - return 0; - } - if (!noscart && scartvoltage > 0 && video_standby == 0) - { - hal_info("%s set SCART_PIN_8 to %dV\n", __FUNCTION__, scartvoltage); - if (ioctl(avsfd, IOC_AVS_SCART_PIN8_SET, scartvoltage) < 0) - perror("IOC_AVS_SCART_PIN8_SET"); - } - close(avsfd); - return 0; -} - -int cVideo::getAspectRatio(void) -{ - VIDEOINFO v; - /* this memset silences *TONS* of valgrind warnings */ - memset(&v, 0, sizeof(v)); - ioctl(fd, MPEG_VID_GET_V_INFO, &v); - if (v.pel_aspect_ratio < VID_DISPSIZE_4x3 || v.pel_aspect_ratio > VID_DISPSIZE_UNKNOWN) - { - hal_info("%s invalid value %d, returning 0/unknown fd: %d", __FUNCTION__, v.pel_aspect_ratio, fd); - return 0; - } - /* convert to Coolstream api values. Taken from streaminfo2.cpp */ - switch (v.pel_aspect_ratio) - { - case VID_DISPSIZE_4x3: - return 1; - case VID_DISPSIZE_16x9: - return 3; - case VID_DISPSIZE_221x100: - return 4; - default: - return 0; - } -} - -int cVideo::setCroppingMode(vidDispMode_t format) -{ - croppingMode = format; - const char *format_string[] = { "norm", "letterbox", "unknown", "mode_1_2", "mode_1_4", "mode_2x", "scale", "disexp" }; - const char *f; - if (format >= VID_DISPMODE_NORM && format <= VID_DISPMODE_DISEXP) - f = format_string[format]; - else - f = "ILLEGAL format!"; - hal_debug("%s(%d) => %s\n", __FUNCTION__, format, f); - return fop(ioctl, MPEG_VID_SET_DISPMODE, format); -} - -int cVideo::Start(void * /*PcrChannel*/, unsigned short /*PcrPid*/, unsigned short /*VideoPid*/, void * /*hChannel*/) -{ - hal_debug("%s playstate=%d\n", __FUNCTION__, playstate); - if (playstate == VIDEO_PLAYING) - return 0; - if (playstate == VIDEO_FREEZED) /* in theory better, but not in practice :-) */ - fop(ioctl, MPEG_VID_CONTINUE); - playstate = VIDEO_PLAYING; - fop(ioctl, MPEG_VID_PLAY); - return fop(ioctl, MPEG_VID_SYNC_ON, VID_SYNC_AUD); -} - -int cVideo::Stop(bool blank) -{ - hal_debug("%s(%d)\n", __FUNCTION__, blank); - if (blank) - { - playstate = VIDEO_STOPPED; - fop(ioctl, MPEG_VID_STOP); - return setBlank(1); - } - playstate = VIDEO_FREEZED; - return fop(ioctl, MPEG_VID_FREEZE); -} - -int cVideo::setBlank(int) -{ - hal_debug("%s\n", __FUNCTION__); - /* The TripleDragon has no VIDEO_SET_BLANK ioctl. - instead, you write a black still-MPEG Iframe into the decoder. - The original software uses different files for 4:3 and 16:9 and - for PAL and NTSC. I optimized that a little bit - */ - int index = 0; /* default PAL */ - int ret = 0; - VIDEOINFO v; - BUFINFO buf; - pthread_mutex_lock(&stillp_mutex); - memset(&v, 0, sizeof(v)); - ioctl(fd, MPEG_VID_GET_V_INFO, &v); - - if ((v.v_size % 240) == 0) /* NTSC */ - { - hal_info("%s NTSC format detected", __FUNCTION__); - index = 1; - } - - if (blank_data[index] == NULL) /* no MPEG found */ - { - ret = -1; - goto out; - } - /* hack: this might work only on those two still-MPEG files! - I diff'ed the 4:3 and the 16:9 still mpeg from the original - soft and spotted the single bit difference, so there is no - need to keep two different MPEGs in memory - If we would read them from disk all the time it would be - slower and it might wake up the drive occasionally */ - if (v.pel_aspect_ratio == VID_DISPSIZE_4x3) - ((char *)blank_data[index])[7] &= ~0x10; // clear the bit - else - ((char *)blank_data[index])[7] |= 0x10; // set the bit - - //WARN("blank[7] == 0x%02x", ((char *)blank_data[index])[7]); - - buf.ulLen = blank_size[index]; - buf.ulStartAdrOff = (int)blank_data[index]; - fop(ioctl, MPEG_VID_STILLP_WRITE, &buf); - ret = fop(ioctl, MPEG_VID_SELECT_SOURCE, VID_SOURCE_DEMUX); - out: - pthread_mutex_unlock(&stillp_mutex); - return ret; -} - -int cVideo::SetVideoSystem(int video_system, bool remember) -{ - hal_info("%s(%d, %d)\n", __FUNCTION__, video_system, remember); - if (video_system > VID_DISPFMT_SECAM || video_system < 0) - video_system = VID_DISPFMT_PAL; - return fop(ioctl, MPEG_VID_SET_DISPFMT, video_system); -} - -int cVideo::getPlayState(void) -{ - return playstate; -} - -void cVideo::SetVideoMode(analog_mode_t mode) -{ - hal_debug("%s(%d)\n", __FUNCTION__, mode); - switch(mode) - { - case ANALOG_SD_YPRPB_SCART: - outputformat = VID_OUTFMT_YBR_SVIDEO; - break; - case ANALOG_SD_RGB_SCART: - outputformat = VID_OUTFMT_RGBC_SVIDEO; - break; - default: - hal_info("%s unknown mode %d\n", __FUNCTION__, mode); - return; - } - fop(ioctl, MPEG_VID_SET_OUTFMT, outputformat); -} - -bool cVideo::ShowPicture(const char * fname) -{ - bool ret = false; - hal_debug("%s(%s)\n", __FUNCTION__, fname); - char destname[512]; - char cmd[512]; - char *p; - void *data; - int mfd; - struct stat st, st2; - strcpy(destname, "/var/cache"); - if (stat(fname, &st2)) - { - hal_info("%s: could not stat %s (%m)\n", __func__, fname); - return ret; - } - mkdir(destname, 0755); - /* the cache filename is (example for /share/tuxbox/neutrino/icons/radiomode.jpg): - /var/cache/share.tuxbox.neutrino.icons.radiomode.jpg.m2v - build that filename first... - TODO: this could cause name clashes, use a hashing function instead... */ - strcat(destname, fname); - p = &destname[strlen("/var/cache/")]; - while ((p = strchr(p, '/')) != NULL) - *p = '.'; - strcat(destname, ".m2v"); - /* ...then check if it exists already... */ - if (stat(destname, &st) || (st.st_mtime != st2.st_mtime) || (st.st_size == 0)) - { - struct utimbuf u; - u.actime = time(NULL); - u.modtime = st2.st_mtime; - /* it does not exist or has a different date, so call ffmpeg... */ - sprintf(cmd, "ffmpeg -y -f mjpeg -i '%s' -s 704x576 '%s' 0) - { - data = malloc(st.st_size); - if (! data) - hal_info("%s malloc failed (%m)\n", __FUNCTION__); - else if (read(mfd, data, st.st_size) != st.st_size) - hal_info("%s short read (%m)\n", __FUNCTION__); - else - { - BUFINFO buf; - buf.ulLen = st.st_size; - buf.ulStartAdrOff = (int)data; - Stop(false); - fop(ioctl, MPEG_VID_STILLP_WRITE, &buf); - ret = true; - } - free(data); - } - close(mfd); - out: - pthread_mutex_unlock(&stillp_mutex); - return ret; -#if 0 - /* DirectFB based picviewer: works, but is slow and the infobar - draws in the same plane */ - int width; - int height; - if (!fname) - return; - - IDirectFBImageProvider *provider; - DFBResult err = dfb->CreateImageProvider(dfb, fname, &provider); - if (err) - { - fprintf(stderr, "cVideo::ShowPicture: CreateImageProvider error!\n"); - return; - } - - DFBSurfaceDescription desc; - provider->GetSurfaceDescription (provider, &desc); - width = desc.width; - height = desc.height; - provider->RenderTo(provider, dfbdest, NULL); - provider->Release(provider); -#endif -} - -void cVideo::StopPicture() -{ - hal_debug("%s\n", __FUNCTION__); - fop(ioctl, MPEG_VID_SELECT_SOURCE, VID_SOURCE_DEMUX); -} - -void cVideo::Standby(unsigned int bOn) -{ - hal_debug("%s(%d)\n", __FUNCTION__, bOn); - if (bOn) - { - setBlank(1); - fop(ioctl, MPEG_VID_SET_OUTFMT, VID_OUTFMT_DISABLE_DACS); - } else - fop(ioctl, MPEG_VID_SET_OUTFMT, outputformat); - routeVideo(bOn); - video_standby = bOn; -} - -int cVideo::getBlank(void) -{ - VIDEOINFO v; - memset(&v, 0, sizeof(v)); - ioctl(fd, MPEG_VID_GET_V_INFO, &v); - /* HACK HACK HACK :-) - * setBlank() puts a 24fps black mpeg into the decoder... - * regular broadcast does not have 24fps, so if it is still - * there, video did not decode... */ - hal_debug("%s: %hu (blank = 2)\n", __func__, v.frame_rate); - return (v.frame_rate == 2); -} - -/* set zoom in percent (100% == 1:1) */ -int cVideo::setZoom(int zoom) -{ - if (zoom == -1) // "auto" reset - zoom = *zoomvalue; - - if (zoom > 150 || zoom < 100) - return -1; - - *zoomvalue = zoom; - - if (zoom == 100) - { - setCroppingMode(croppingMode); - return fop(ioctl, MPEG_VID_SCALE_OFF); - } - - /* the SCALEINFO describes the source and destination of the scaled - video. "src" is the part of the source picture that gets scaled, - "dst" is the area on the screen where this part is displayed - Messing around with MPEG_VID_SET_SCALE_POS disables the automatic - letterboxing, which, as I guess, is only a special case of - MPEG_VID_SET_SCALE_POS. Therefor we need to care for letterboxing - etc here, which is probably not yet totally correct */ - SCALEINFO s; - memset(&s, 0, sizeof(s)); - if (zoom > 100) - { - /* 1 = 4:3, 3 = 16:9, 4 = 2.21:1, 0 = unknown */ - int x = getAspectRatio(); - if (x < 3 && croppingMode == VID_DISPMODE_NORM) - { - s.src.hori_size = 720; - s.des.hori_size = 720 * 3/4 * zoom / 100; - if (s.des.hori_size > 720) - { - /* the destination exceeds the screen size. - TODO: decrease source size to allow higher - zoom factors (is this useful ?) */ - s.des.hori_size = 720; - zoom = 133; // (720*4*100)/(720*3) - *zoomvalue = zoom; - } - } - else - { - s.src.hori_size = 2 * 720 - 720 * zoom / 100; - s.des.hori_size = 720; - } - s.src.vert_size = 2 * 576 - 576 * zoom / 100; - s.des.hori_off = (720 - s.des.hori_size) / 2; - s.des.vert_size = 576; - } -/* not working correctly (wrong formula) and does not make sense IMHO - else - { - s.src.hori_size = 720; - s.src.vert_size = 576; - s.des.hori_size = 720 * zoom / 100; - s.des.vert_size = 576 * zoom / 100; - s.des.hori_off = (720 - s.des.hori_size) / 2; - s.des.vert_off = (576 - s.des.vert_size) / 2; - } - */ - hal_debug("%s %d%% src: %d:%d:%d:%d dst: %d:%d:%d:%d\n", __FUNCTION__, zoom, - s.src.hori_off,s.src.vert_off,s.src.hori_size,s.src.vert_size, - s.des.hori_off,s.des.vert_off,s.des.hori_size,s.des.vert_size); - fop(ioctl, MPEG_VID_SET_DISPMODE, VID_DISPMODE_SCALE); - fop(ioctl, MPEG_VID_SCALE_ON); - return fop(ioctl, MPEG_VID_SET_SCALE_POS, &s); -} - -#if 0 -int cVideo::getZoom(void) -{ - return *zoomvalue; -} - -void cVideo::setZoomAspect(int index) -{ - if (index < 0 || index > 1) - WARN("index out of range"); - else - zoomvalue = &z[index]; -} -#endif - -/* this function is regularly called, checks if video parameters - changed and triggers appropriate actions */ -void cVideo::VideoParamWatchdog(void) -{ - static unsigned int _v_info = (unsigned int) -1; - unsigned int v_info; - if (fd == -1) - return; - ioctl(fd, MPEG_VID_GET_V_INFO_RAW, &v_info); - if (_v_info != v_info) - { - hal_debug("%s params changed. old: %08x new: %08x\n", __FUNCTION__, _v_info, v_info); - setAspectRatio(-1, -1); - } - _v_info = v_info; -} - -void cVideo::Pig(int x, int y, int w, int h, int /*osd_w*/, int /*osd_h*/) -{ - /* x = y = w = h = -1 -> reset / "hide" PIG */ - if (x == -1 && y == -1 && w == -1 && h == -1) - { - setZoom(-1); - setAspectRatio(-1, -1); - return; - } - SCALEINFO s; - memset(&s, 0, sizeof(s)); - s.src.hori_size = 720; - s.src.vert_size = 576; - s.des.hori_off = x; - s.des.vert_off = y; - s.des.hori_size = w; - s.des.vert_size = h; - hal_debug("%s src: %d:%d:%d:%d dst: %d:%d:%d:%d", __FUNCTION__, - s.src.hori_off,s.src.vert_off,s.src.hori_size,s.src.vert_size, - s.des.hori_off,s.des.vert_off,s.des.hori_size,s.des.vert_size); - fop(ioctl, MPEG_VID_SET_DISPMODE, VID_DISPMODE_SCALE); - fop(ioctl, MPEG_VID_SCALE_ON); - fop(ioctl, MPEG_VID_SET_SCALE_POS, &s); -} - -void cVideo::getPictureInfo(int &width, int &height, int &rate) -{ - VIDEOINFO v; - /* this memset silences *TONS* of valgrind warnings */ - memset(&v, 0, sizeof(v)); - ioctl(fd, MPEG_VID_GET_V_INFO, &v); - /* convert to Coolstream API */ - rate = (int)v.frame_rate - 1; - width = (int)v.h_size; - height = (int)v.v_size; -} - -void cVideo::SetSyncMode(AVSYNC_TYPE Mode) -{ - hal_debug("%s %d\n", __FUNCTION__, Mode); - /* - * { 0, LOCALE_OPTIONS_OFF }, - * { 1, LOCALE_OPTIONS_ON }, - * { 2, LOCALE_AUDIOMENU_AVSYNC_AM } - */ - switch(Mode) - { - case 0: - ioctl(fd, MPEG_VID_SYNC_OFF); - break; - case 1: - ioctl(fd, MPEG_VID_SYNC_ON, VID_SYNC_VID); - break; - default: - ioctl(fd, MPEG_VID_SYNC_ON, VID_SYNC_AUD); - break; - } -}; - -int cVideo::SetStreamType(VIDEO_FORMAT type) -{ - static const char *VF[] = { - "VIDEO_FORMAT_MPEG2", - "VIDEO_FORMAT_MPEG4", - "VIDEO_FORMAT_VC1", - "VIDEO_FORMAT_JPEG", - "VIDEO_FORMAT_GIF", - "VIDEO_FORMAT_PNG" - }; - - hal_debug("%s type=%s\n", __FUNCTION__, VF[type]); - return 0; -} - -void cVideo::routeVideo(int standby) -{ - hal_debug("%s(%d)\n", __FUNCTION__, standby); - - int avsfd = open("/dev/stb/tdsystem", O_RDONLY); - if (avsfd < 0) - { - perror("open tdsystem"); - return; - } - - /* in standby, we always route VCR scart to the TV. Once there is a UI - to configure this, we can think more about this... */ - if (standby) - { - hal_info("%s set fastblank and pin8 to follow VCR SCART, route VCR to TV\n", __FUNCTION__); - if (ioctl(avsfd, IOC_AVS_FASTBLANK_SET, (unsigned char)3) < 0) - perror("IOC_AVS_FASTBLANK_SET, 3"); - /* TODO: should probably depend on aspect ratio setting */ - if (ioctl(avsfd, IOC_AVS_SCART_PIN8_FOLLOW_VCR) < 0) - perror("IOC_AVS_SCART_PIN8_FOLLOW_VCR"); - if (ioctl(avsfd, IOC_AVS_ROUTE_VCR2TV) < 0) - perror("IOC_AVS_ROUTE_VCR2TV"); - } else { - unsigned char fblk = 1; - hal_info("%s set fastblank=%d pin8=%dV, route encoder to TV\n", __FUNCTION__, fblk, scartvoltage); - if (ioctl(avsfd, IOC_AVS_FASTBLANK_SET, fblk) < 0) - perror("IOC_AVS_FASTBLANK_SET, fblk"); - if (!noscart && ioctl(avsfd, IOC_AVS_SCART_PIN8_SET, scartvoltage) < 0) - perror("IOC_AVS_SCART_PIN8_SET"); - if (ioctl(avsfd, IOC_AVS_ROUTE_ENC2TV) < 0) - perror("IOC_AVS_ROUTE_ENC2TV"); - } - close(avsfd); -} - -void cVideo::FastForwardMode(int mode) -{ - hal_debug("%s\n", __FUNCTION__); - fop(ioctl, MPEG_VID_FASTFORWARD, mode); -} - -/* get an image of the video screen - * this code is inspired by dreambox AIO-grab, - * git://schwerkraft.elitedvb.net/aio-grab/aio-grab.git */ -/* static lookup tables for faster yuv2rgb conversion */ -static const int yuv2rgbtable_y[256] = { - 0xFFED5EA0, 0xFFEE88B6, 0xFFEFB2CC, 0xFFF0DCE2, 0xFFF206F8, 0xFFF3310E, 0xFFF45B24, 0xFFF5853A, - 0xFFF6AF50, 0xFFF7D966, 0xFFF9037C, 0xFFFA2D92, 0xFFFB57A8, 0xFFFC81BE, 0xFFFDABD4, 0xFFFED5EA, - 0x00000000, 0x00012A16, 0x0002542C, 0x00037E42, 0x0004A858, 0x0005D26E, 0x0006FC84, 0x0008269A, - 0x000950B0, 0x000A7AC6, 0x000BA4DC, 0x000CCEF2, 0x000DF908, 0x000F231E, 0x00104D34, 0x0011774A, - 0x0012A160, 0x0013CB76, 0x0014F58C, 0x00161FA2, 0x001749B8, 0x001873CE, 0x00199DE4, 0x001AC7FA, - 0x001BF210, 0x001D1C26, 0x001E463C, 0x001F7052, 0x00209A68, 0x0021C47E, 0x0022EE94, 0x002418AA, - 0x002542C0, 0x00266CD6, 0x002796EC, 0x0028C102, 0x0029EB18, 0x002B152E, 0x002C3F44, 0x002D695A, - 0x002E9370, 0x002FBD86, 0x0030E79C, 0x003211B2, 0x00333BC8, 0x003465DE, 0x00358FF4, 0x0036BA0A, - 0x0037E420, 0x00390E36, 0x003A384C, 0x003B6262, 0x003C8C78, 0x003DB68E, 0x003EE0A4, 0x00400ABA, - 0x004134D0, 0x00425EE6, 0x004388FC, 0x0044B312, 0x0045DD28, 0x0047073E, 0x00483154, 0x00495B6A, - 0x004A8580, 0x004BAF96, 0x004CD9AC, 0x004E03C2, 0x004F2DD8, 0x005057EE, 0x00518204, 0x0052AC1A, - 0x0053D630, 0x00550046, 0x00562A5C, 0x00575472, 0x00587E88, 0x0059A89E, 0x005AD2B4, 0x005BFCCA, - 0x005D26E0, 0x005E50F6, 0x005F7B0C, 0x0060A522, 0x0061CF38, 0x0062F94E, 0x00642364, 0x00654D7A, - 0x00667790, 0x0067A1A6, 0x0068CBBC, 0x0069F5D2, 0x006B1FE8, 0x006C49FE, 0x006D7414, 0x006E9E2A, - 0x006FC840, 0x0070F256, 0x00721C6C, 0x00734682, 0x00747098, 0x00759AAE, 0x0076C4C4, 0x0077EEDA, - 0x007918F0, 0x007A4306, 0x007B6D1C, 0x007C9732, 0x007DC148, 0x007EEB5E, 0x00801574, 0x00813F8A, - 0x008269A0, 0x008393B6, 0x0084BDCC, 0x0085E7E2, 0x008711F8, 0x00883C0E, 0x00896624, 0x008A903A, - 0x008BBA50, 0x008CE466, 0x008E0E7C, 0x008F3892, 0x009062A8, 0x00918CBE, 0x0092B6D4, 0x0093E0EA, - 0x00950B00, 0x00963516, 0x00975F2C, 0x00988942, 0x0099B358, 0x009ADD6E, 0x009C0784, 0x009D319A, - 0x009E5BB0, 0x009F85C6, 0x00A0AFDC, 0x00A1D9F2, 0x00A30408, 0x00A42E1E, 0x00A55834, 0x00A6824A, - 0x00A7AC60, 0x00A8D676, 0x00AA008C, 0x00AB2AA2, 0x00AC54B8, 0x00AD7ECE, 0x00AEA8E4, 0x00AFD2FA, - 0x00B0FD10, 0x00B22726, 0x00B3513C, 0x00B47B52, 0x00B5A568, 0x00B6CF7E, 0x00B7F994, 0x00B923AA, - 0x00BA4DC0, 0x00BB77D6, 0x00BCA1EC, 0x00BDCC02, 0x00BEF618, 0x00C0202E, 0x00C14A44, 0x00C2745A, - 0x00C39E70, 0x00C4C886, 0x00C5F29C, 0x00C71CB2, 0x00C846C8, 0x00C970DE, 0x00CA9AF4, 0x00CBC50A, - 0x00CCEF20, 0x00CE1936, 0x00CF434C, 0x00D06D62, 0x00D19778, 0x00D2C18E, 0x00D3EBA4, 0x00D515BA, - 0x00D63FD0, 0x00D769E6, 0x00D893FC, 0x00D9BE12, 0x00DAE828, 0x00DC123E, 0x00DD3C54, 0x00DE666A, - 0x00DF9080, 0x00E0BA96, 0x00E1E4AC, 0x00E30EC2, 0x00E438D8, 0x00E562EE, 0x00E68D04, 0x00E7B71A, - 0x00E8E130, 0x00EA0B46, 0x00EB355C, 0x00EC5F72, 0x00ED8988, 0x00EEB39E, 0x00EFDDB4, 0x00F107CA, - 0x00F231E0, 0x00F35BF6, 0x00F4860C, 0x00F5B022, 0x00F6DA38, 0x00F8044E, 0x00F92E64, 0x00FA587A, - 0x00FB8290, 0x00FCACA6, 0x00FDD6BC, 0x00FF00D2, 0x01002AE8, 0x010154FE, 0x01027F14, 0x0103A92A, - 0x0104D340, 0x0105FD56, 0x0107276C, 0x01085182, 0x01097B98, 0x010AA5AE, 0x010BCFC4, 0x010CF9DA, - 0x010E23F0, 0x010F4E06, 0x0110781C, 0x0111A232, 0x0112CC48, 0x0113F65E, 0x01152074, 0x01164A8A -}; -static const int yuv2rgbtable_ru[256] = { - 0xFEFDA500, 0xFEFFA9B6, 0xFF01AE6C, 0xFF03B322, 0xFF05B7D8, 0xFF07BC8E, 0xFF09C144, 0xFF0BC5FA, - 0xFF0DCAB0, 0xFF0FCF66, 0xFF11D41C, 0xFF13D8D2, 0xFF15DD88, 0xFF17E23E, 0xFF19E6F4, 0xFF1BEBAA, - 0xFF1DF060, 0xFF1FF516, 0xFF21F9CC, 0xFF23FE82, 0xFF260338, 0xFF2807EE, 0xFF2A0CA4, 0xFF2C115A, - 0xFF2E1610, 0xFF301AC6, 0xFF321F7C, 0xFF342432, 0xFF3628E8, 0xFF382D9E, 0xFF3A3254, 0xFF3C370A, - 0xFF3E3BC0, 0xFF404076, 0xFF42452C, 0xFF4449E2, 0xFF464E98, 0xFF48534E, 0xFF4A5804, 0xFF4C5CBA, - 0xFF4E6170, 0xFF506626, 0xFF526ADC, 0xFF546F92, 0xFF567448, 0xFF5878FE, 0xFF5A7DB4, 0xFF5C826A, - 0xFF5E8720, 0xFF608BD6, 0xFF62908C, 0xFF649542, 0xFF6699F8, 0xFF689EAE, 0xFF6AA364, 0xFF6CA81A, - 0xFF6EACD0, 0xFF70B186, 0xFF72B63C, 0xFF74BAF2, 0xFF76BFA8, 0xFF78C45E, 0xFF7AC914, 0xFF7CCDCA, - 0xFF7ED280, 0xFF80D736, 0xFF82DBEC, 0xFF84E0A2, 0xFF86E558, 0xFF88EA0E, 0xFF8AEEC4, 0xFF8CF37A, - 0xFF8EF830, 0xFF90FCE6, 0xFF93019C, 0xFF950652, 0xFF970B08, 0xFF990FBE, 0xFF9B1474, 0xFF9D192A, - 0xFF9F1DE0, 0xFFA12296, 0xFFA3274C, 0xFFA52C02, 0xFFA730B8, 0xFFA9356E, 0xFFAB3A24, 0xFFAD3EDA, - 0xFFAF4390, 0xFFB14846, 0xFFB34CFC, 0xFFB551B2, 0xFFB75668, 0xFFB95B1E, 0xFFBB5FD4, 0xFFBD648A, - 0xFFBF6940, 0xFFC16DF6, 0xFFC372AC, 0xFFC57762, 0xFFC77C18, 0xFFC980CE, 0xFFCB8584, 0xFFCD8A3A, - 0xFFCF8EF0, 0xFFD193A6, 0xFFD3985C, 0xFFD59D12, 0xFFD7A1C8, 0xFFD9A67E, 0xFFDBAB34, 0xFFDDAFEA, - 0xFFDFB4A0, 0xFFE1B956, 0xFFE3BE0C, 0xFFE5C2C2, 0xFFE7C778, 0xFFE9CC2E, 0xFFEBD0E4, 0xFFEDD59A, - 0xFFEFDA50, 0xFFF1DF06, 0xFFF3E3BC, 0xFFF5E872, 0xFFF7ED28, 0xFFF9F1DE, 0xFFFBF694, 0xFFFDFB4A, - 0x00000000, 0x000204B6, 0x0004096C, 0x00060E22, 0x000812D8, 0x000A178E, 0x000C1C44, 0x000E20FA, - 0x001025B0, 0x00122A66, 0x00142F1C, 0x001633D2, 0x00183888, 0x001A3D3E, 0x001C41F4, 0x001E46AA, - 0x00204B60, 0x00225016, 0x002454CC, 0x00265982, 0x00285E38, 0x002A62EE, 0x002C67A4, 0x002E6C5A, - 0x00307110, 0x003275C6, 0x00347A7C, 0x00367F32, 0x003883E8, 0x003A889E, 0x003C8D54, 0x003E920A, - 0x004096C0, 0x00429B76, 0x0044A02C, 0x0046A4E2, 0x0048A998, 0x004AAE4E, 0x004CB304, 0x004EB7BA, - 0x0050BC70, 0x0052C126, 0x0054C5DC, 0x0056CA92, 0x0058CF48, 0x005AD3FE, 0x005CD8B4, 0x005EDD6A, - 0x0060E220, 0x0062E6D6, 0x0064EB8C, 0x0066F042, 0x0068F4F8, 0x006AF9AE, 0x006CFE64, 0x006F031A, - 0x007107D0, 0x00730C86, 0x0075113C, 0x007715F2, 0x00791AA8, 0x007B1F5E, 0x007D2414, 0x007F28CA, - 0x00812D80, 0x00833236, 0x008536EC, 0x00873BA2, 0x00894058, 0x008B450E, 0x008D49C4, 0x008F4E7A, - 0x00915330, 0x009357E6, 0x00955C9C, 0x00976152, 0x00996608, 0x009B6ABE, 0x009D6F74, 0x009F742A, - 0x00A178E0, 0x00A37D96, 0x00A5824C, 0x00A78702, 0x00A98BB8, 0x00AB906E, 0x00AD9524, 0x00AF99DA, - 0x00B19E90, 0x00B3A346, 0x00B5A7FC, 0x00B7ACB2, 0x00B9B168, 0x00BBB61E, 0x00BDBAD4, 0x00BFBF8A, - 0x00C1C440, 0x00C3C8F6, 0x00C5CDAC, 0x00C7D262, 0x00C9D718, 0x00CBDBCE, 0x00CDE084, 0x00CFE53A, - 0x00D1E9F0, 0x00D3EEA6, 0x00D5F35C, 0x00D7F812, 0x00D9FCC8, 0x00DC017E, 0x00DE0634, 0x00E00AEA, - 0x00E20FA0, 0x00E41456, 0x00E6190C, 0x00E81DC2, 0x00EA2278, 0x00EC272E, 0x00EE2BE4, 0x00F0309A, - 0x00F23550, 0x00F43A06, 0x00F63EBC, 0x00F84372, 0x00FA4828, 0x00FC4CDE, 0x00FE5194, 0x00100564A -}; -static const int yuv2rgbtable_gu[256] = { - 0xFFCDD300, 0xFFCE375A, 0xFFCE9BB4, 0xFFCF000E, 0xFFCF6468, 0xFFCFC8C2, 0xFFD02D1C, 0xFFD09176, - 0xFFD0F5D0, 0xFFD15A2A, 0xFFD1BE84, 0xFFD222DE, 0xFFD28738, 0xFFD2EB92, 0xFFD34FEC, 0xFFD3B446, - 0xFFD418A0, 0xFFD47CFA, 0xFFD4E154, 0xFFD545AE, 0xFFD5AA08, 0xFFD60E62, 0xFFD672BC, 0xFFD6D716, - 0xFFD73B70, 0xFFD79FCA, 0xFFD80424, 0xFFD8687E, 0xFFD8CCD8, 0xFFD93132, 0xFFD9958C, 0xFFD9F9E6, - 0xFFDA5E40, 0xFFDAC29A, 0xFFDB26F4, 0xFFDB8B4E, 0xFFDBEFA8, 0xFFDC5402, 0xFFDCB85C, 0xFFDD1CB6, - 0xFFDD8110, 0xFFDDE56A, 0xFFDE49C4, 0xFFDEAE1E, 0xFFDF1278, 0xFFDF76D2, 0xFFDFDB2C, 0xFFE03F86, - 0xFFE0A3E0, 0xFFE1083A, 0xFFE16C94, 0xFFE1D0EE, 0xFFE23548, 0xFFE299A2, 0xFFE2FDFC, 0xFFE36256, - 0xFFE3C6B0, 0xFFE42B0A, 0xFFE48F64, 0xFFE4F3BE, 0xFFE55818, 0xFFE5BC72, 0xFFE620CC, 0xFFE68526, - 0xFFE6E980, 0xFFE74DDA, 0xFFE7B234, 0xFFE8168E, 0xFFE87AE8, 0xFFE8DF42, 0xFFE9439C, 0xFFE9A7F6, - 0xFFEA0C50, 0xFFEA70AA, 0xFFEAD504, 0xFFEB395E, 0xFFEB9DB8, 0xFFEC0212, 0xFFEC666C, 0xFFECCAC6, - 0xFFED2F20, 0xFFED937A, 0xFFEDF7D4, 0xFFEE5C2E, 0xFFEEC088, 0xFFEF24E2, 0xFFEF893C, 0xFFEFED96, - 0xFFF051F0, 0xFFF0B64A, 0xFFF11AA4, 0xFFF17EFE, 0xFFF1E358, 0xFFF247B2, 0xFFF2AC0C, 0xFFF31066, - 0xFFF374C0, 0xFFF3D91A, 0xFFF43D74, 0xFFF4A1CE, 0xFFF50628, 0xFFF56A82, 0xFFF5CEDC, 0xFFF63336, - 0xFFF69790, 0xFFF6FBEA, 0xFFF76044, 0xFFF7C49E, 0xFFF828F8, 0xFFF88D52, 0xFFF8F1AC, 0xFFF95606, - 0xFFF9BA60, 0xFFFA1EBA, 0xFFFA8314, 0xFFFAE76E, 0xFFFB4BC8, 0xFFFBB022, 0xFFFC147C, 0xFFFC78D6, - 0xFFFCDD30, 0xFFFD418A, 0xFFFDA5E4, 0xFFFE0A3E, 0xFFFE6E98, 0xFFFED2F2, 0xFFFF374C, 0xFFFF9BA6, - 0x00000000, 0x0000645A, 0x0000C8B4, 0x00012D0E, 0x00019168, 0x0001F5C2, 0x00025A1C, 0x0002BE76, - 0x000322D0, 0x0003872A, 0x0003EB84, 0x00044FDE, 0x0004B438, 0x00051892, 0x00057CEC, 0x0005E146, - 0x000645A0, 0x0006A9FA, 0x00070E54, 0x000772AE, 0x0007D708, 0x00083B62, 0x00089FBC, 0x00090416, - 0x00096870, 0x0009CCCA, 0x000A3124, 0x000A957E, 0x000AF9D8, 0x000B5E32, 0x000BC28C, 0x000C26E6, - 0x000C8B40, 0x000CEF9A, 0x000D53F4, 0x000DB84E, 0x000E1CA8, 0x000E8102, 0x000EE55C, 0x000F49B6, - 0x000FAE10, 0x0010126A, 0x001076C4, 0x0010DB1E, 0x00113F78, 0x0011A3D2, 0x0012082C, 0x00126C86, - 0x0012D0E0, 0x0013353A, 0x00139994, 0x0013FDEE, 0x00146248, 0x0014C6A2, 0x00152AFC, 0x00158F56, - 0x0015F3B0, 0x0016580A, 0x0016BC64, 0x001720BE, 0x00178518, 0x0017E972, 0x00184DCC, 0x0018B226, - 0x00191680, 0x00197ADA, 0x0019DF34, 0x001A438E, 0x001AA7E8, 0x001B0C42, 0x001B709C, 0x001BD4F6, - 0x001C3950, 0x001C9DAA, 0x001D0204, 0x001D665E, 0x001DCAB8, 0x001E2F12, 0x001E936C, 0x001EF7C6, - 0x001F5C20, 0x001FC07A, 0x002024D4, 0x0020892E, 0x0020ED88, 0x002151E2, 0x0021B63C, 0x00221A96, - 0x00227EF0, 0x0022E34A, 0x002347A4, 0x0023ABFE, 0x00241058, 0x002474B2, 0x0024D90C, 0x00253D66, - 0x0025A1C0, 0x0026061A, 0x00266A74, 0x0026CECE, 0x00273328, 0x00279782, 0x0027FBDC, 0x00286036, - 0x0028C490, 0x002928EA, 0x00298D44, 0x0029F19E, 0x002A55F8, 0x002ABA52, 0x002B1EAC, 0x002B8306, - 0x002BE760, 0x002C4BBA, 0x002CB014, 0x002D146E, 0x002D78C8, 0x002DDD22, 0x002E417C, 0x002EA5D6, - 0x002F0A30, 0x002F6E8A, 0x002FD2E4, 0x0030373E, 0x00309B98, 0x0030FFF2, 0x0031644C, 0x0031C8A6 -}; -static const int yuv2rgbtable_gv[256] = { - 0xFF97E900, 0xFF98B92E, 0xFF99895C, 0xFF9A598A, 0xFF9B29B8, 0xFF9BF9E6, 0xFF9CCA14, 0xFF9D9A42, - 0xFF9E6A70, 0xFF9F3A9E, 0xFFA00ACC, 0xFFA0DAFA, 0xFFA1AB28, 0xFFA27B56, 0xFFA34B84, 0xFFA41BB2, - 0xFFA4EBE0, 0xFFA5BC0E, 0xFFA68C3C, 0xFFA75C6A, 0xFFA82C98, 0xFFA8FCC6, 0xFFA9CCF4, 0xFFAA9D22, - 0xFFAB6D50, 0xFFAC3D7E, 0xFFAD0DAC, 0xFFADDDDA, 0xFFAEAE08, 0xFFAF7E36, 0xFFB04E64, 0xFFB11E92, - 0xFFB1EEC0, 0xFFB2BEEE, 0xFFB38F1C, 0xFFB45F4A, 0xFFB52F78, 0xFFB5FFA6, 0xFFB6CFD4, 0xFFB7A002, - 0xFFB87030, 0xFFB9405E, 0xFFBA108C, 0xFFBAE0BA, 0xFFBBB0E8, 0xFFBC8116, 0xFFBD5144, 0xFFBE2172, - 0xFFBEF1A0, 0xFFBFC1CE, 0xFFC091FC, 0xFFC1622A, 0xFFC23258, 0xFFC30286, 0xFFC3D2B4, 0xFFC4A2E2, - 0xFFC57310, 0xFFC6433E, 0xFFC7136C, 0xFFC7E39A, 0xFFC8B3C8, 0xFFC983F6, 0xFFCA5424, 0xFFCB2452, - 0xFFCBF480, 0xFFCCC4AE, 0xFFCD94DC, 0xFFCE650A, 0xFFCF3538, 0xFFD00566, 0xFFD0D594, 0xFFD1A5C2, - 0xFFD275F0, 0xFFD3461E, 0xFFD4164C, 0xFFD4E67A, 0xFFD5B6A8, 0xFFD686D6, 0xFFD75704, 0xFFD82732, - 0xFFD8F760, 0xFFD9C78E, 0xFFDA97BC, 0xFFDB67EA, 0xFFDC3818, 0xFFDD0846, 0xFFDDD874, 0xFFDEA8A2, - 0xFFDF78D0, 0xFFE048FE, 0xFFE1192C, 0xFFE1E95A, 0xFFE2B988, 0xFFE389B6, 0xFFE459E4, 0xFFE52A12, - 0xFFE5FA40, 0xFFE6CA6E, 0xFFE79A9C, 0xFFE86ACA, 0xFFE93AF8, 0xFFEA0B26, 0xFFEADB54, 0xFFEBAB82, - 0xFFEC7BB0, 0xFFED4BDE, 0xFFEE1C0C, 0xFFEEEC3A, 0xFFEFBC68, 0xFFF08C96, 0xFFF15CC4, 0xFFF22CF2, - 0xFFF2FD20, 0xFFF3CD4E, 0xFFF49D7C, 0xFFF56DAA, 0xFFF63DD8, 0xFFF70E06, 0xFFF7DE34, 0xFFF8AE62, - 0xFFF97E90, 0xFFFA4EBE, 0xFFFB1EEC, 0xFFFBEF1A, 0xFFFCBF48, 0xFFFD8F76, 0xFFFE5FA4, 0xFFFF2FD2, - 0x00000000, 0x0000D02E, 0x0001A05C, 0x0002708A, 0x000340B8, 0x000410E6, 0x0004E114, 0x0005B142, - 0x00068170, 0x0007519E, 0x000821CC, 0x0008F1FA, 0x0009C228, 0x000A9256, 0x000B6284, 0x000C32B2, - 0x000D02E0, 0x000DD30E, 0x000EA33C, 0x000F736A, 0x00104398, 0x001113C6, 0x0011E3F4, 0x0012B422, - 0x00138450, 0x0014547E, 0x001524AC, 0x0015F4DA, 0x0016C508, 0x00179536, 0x00186564, 0x00193592, - 0x001A05C0, 0x001AD5EE, 0x001BA61C, 0x001C764A, 0x001D4678, 0x001E16A6, 0x001EE6D4, 0x001FB702, - 0x00208730, 0x0021575E, 0x0022278C, 0x0022F7BA, 0x0023C7E8, 0x00249816, 0x00256844, 0x00263872, - 0x002708A0, 0x0027D8CE, 0x0028A8FC, 0x0029792A, 0x002A4958, 0x002B1986, 0x002BE9B4, 0x002CB9E2, - 0x002D8A10, 0x002E5A3E, 0x002F2A6C, 0x002FFA9A, 0x0030CAC8, 0x00319AF6, 0x00326B24, 0x00333B52, - 0x00340B80, 0x0034DBAE, 0x0035ABDC, 0x00367C0A, 0x00374C38, 0x00381C66, 0x0038EC94, 0x0039BCC2, - 0x003A8CF0, 0x003B5D1E, 0x003C2D4C, 0x003CFD7A, 0x003DCDA8, 0x003E9DD6, 0x003F6E04, 0x00403E32, - 0x00410E60, 0x0041DE8E, 0x0042AEBC, 0x00437EEA, 0x00444F18, 0x00451F46, 0x0045EF74, 0x0046BFA2, - 0x00478FD0, 0x00485FFE, 0x0049302C, 0x004A005A, 0x004AD088, 0x004BA0B6, 0x004C70E4, 0x004D4112, - 0x004E1140, 0x004EE16E, 0x004FB19C, 0x005081CA, 0x005151F8, 0x00522226, 0x0052F254, 0x0053C282, - 0x005492B0, 0x005562DE, 0x0056330C, 0x0057033A, 0x0057D368, 0x0058A396, 0x005973C4, 0x005A43F2, - 0x005B1420, 0x005BE44E, 0x005CB47C, 0x005D84AA, 0x005E54D8, 0x005F2506, 0x005FF534, 0x0060C562, - 0x00619590, 0x006265BE, 0x006335EC, 0x0064061A, 0x0064D648, 0x0065A676, 0x006676A4, 0x006746D2 -}; -static const int yuv2rgbtable_bv[256] = { - 0xFF33A280, 0xFF353B3B, 0xFF36D3F6, 0xFF386CB1, 0xFF3A056C, 0xFF3B9E27, 0xFF3D36E2, 0xFF3ECF9D, - 0xFF406858, 0xFF420113, 0xFF4399CE, 0xFF453289, 0xFF46CB44, 0xFF4863FF, 0xFF49FCBA, 0xFF4B9575, - 0xFF4D2E30, 0xFF4EC6EB, 0xFF505FA6, 0xFF51F861, 0xFF53911C, 0xFF5529D7, 0xFF56C292, 0xFF585B4D, - 0xFF59F408, 0xFF5B8CC3, 0xFF5D257E, 0xFF5EBE39, 0xFF6056F4, 0xFF61EFAF, 0xFF63886A, 0xFF652125, - 0xFF66B9E0, 0xFF68529B, 0xFF69EB56, 0xFF6B8411, 0xFF6D1CCC, 0xFF6EB587, 0xFF704E42, 0xFF71E6FD, - 0xFF737FB8, 0xFF751873, 0xFF76B12E, 0xFF7849E9, 0xFF79E2A4, 0xFF7B7B5F, 0xFF7D141A, 0xFF7EACD5, - 0xFF804590, 0xFF81DE4B, 0xFF837706, 0xFF850FC1, 0xFF86A87C, 0xFF884137, 0xFF89D9F2, 0xFF8B72AD, - 0xFF8D0B68, 0xFF8EA423, 0xFF903CDE, 0xFF91D599, 0xFF936E54, 0xFF95070F, 0xFF969FCA, 0xFF983885, - 0xFF99D140, 0xFF9B69FB, 0xFF9D02B6, 0xFF9E9B71, 0xFFA0342C, 0xFFA1CCE7, 0xFFA365A2, 0xFFA4FE5D, - 0xFFA69718, 0xFFA82FD3, 0xFFA9C88E, 0xFFAB6149, 0xFFACFA04, 0xFFAE92BF, 0xFFB02B7A, 0xFFB1C435, - 0xFFB35CF0, 0xFFB4F5AB, 0xFFB68E66, 0xFFB82721, 0xFFB9BFDC, 0xFFBB5897, 0xFFBCF152, 0xFFBE8A0D, - 0xFFC022C8, 0xFFC1BB83, 0xFFC3543E, 0xFFC4ECF9, 0xFFC685B4, 0xFFC81E6F, 0xFFC9B72A, 0xFFCB4FE5, - 0xFFCCE8A0, 0xFFCE815B, 0xFFD01A16, 0xFFD1B2D1, 0xFFD34B8C, 0xFFD4E447, 0xFFD67D02, 0xFFD815BD, - 0xFFD9AE78, 0xFFDB4733, 0xFFDCDFEE, 0xFFDE78A9, 0xFFE01164, 0xFFE1AA1F, 0xFFE342DA, 0xFFE4DB95, - 0xFFE67450, 0xFFE80D0B, 0xFFE9A5C6, 0xFFEB3E81, 0xFFECD73C, 0xFFEE6FF7, 0xFFF008B2, 0xFFF1A16D, - 0xFFF33A28, 0xFFF4D2E3, 0xFFF66B9E, 0xFFF80459, 0xFFF99D14, 0xFFFB35CF, 0xFFFCCE8A, 0xFFFE6745, - 0x00000000, 0x000198BB, 0x00033176, 0x0004CA31, 0x000662EC, 0x0007FBA7, 0x00099462, 0x000B2D1D, - 0x000CC5D8, 0x000E5E93, 0x000FF74E, 0x00119009, 0x001328C4, 0x0014C17F, 0x00165A3A, 0x0017F2F5, - 0x00198BB0, 0x001B246B, 0x001CBD26, 0x001E55E1, 0x001FEE9C, 0x00218757, 0x00232012, 0x0024B8CD, - 0x00265188, 0x0027EA43, 0x002982FE, 0x002B1BB9, 0x002CB474, 0x002E4D2F, 0x002FE5EA, 0x00317EA5, - 0x00331760, 0x0034B01B, 0x003648D6, 0x0037E191, 0x00397A4C, 0x003B1307, 0x003CABC2, 0x003E447D, - 0x003FDD38, 0x004175F3, 0x00430EAE, 0x0044A769, 0x00464024, 0x0047D8DF, 0x0049719A, 0x004B0A55, - 0x004CA310, 0x004E3BCB, 0x004FD486, 0x00516D41, 0x005305FC, 0x00549EB7, 0x00563772, 0x0057D02D, - 0x005968E8, 0x005B01A3, 0x005C9A5E, 0x005E3319, 0x005FCBD4, 0x0061648F, 0x0062FD4A, 0x00649605, - 0x00662EC0, 0x0067C77B, 0x00696036, 0x006AF8F1, 0x006C91AC, 0x006E2A67, 0x006FC322, 0x00715BDD, - 0x0072F498, 0x00748D53, 0x0076260E, 0x0077BEC9, 0x00795784, 0x007AF03F, 0x007C88FA, 0x007E21B5, - 0x007FBA70, 0x0081532B, 0x0082EBE6, 0x008484A1, 0x00861D5C, 0x0087B617, 0x00894ED2, 0x008AE78D, - 0x008C8048, 0x008E1903, 0x008FB1BE, 0x00914A79, 0x0092E334, 0x00947BEF, 0x009614AA, 0x0097AD65, - 0x00994620, 0x009ADEDB, 0x009C7796, 0x009E1051, 0x009FA90C, 0x00A141C7, 0x00A2DA82, 0x00A4733D, - 0x00A60BF8, 0x00A7A4B3, 0x00A93D6E, 0x00AAD629, 0x00AC6EE4, 0x00AE079F, 0x00AFA05A, 0x00B13915, - 0x00B2D1D0, 0x00B46A8B, 0x00B60346, 0x00B79C01, 0x00B934BC, 0x00BACD77, 0x00BC6632, 0x00BDFEED, - 0x00BF97A8, 0x00C13063, 0x00C2C91E, 0x00C461D9, 0x00C5FA94, 0x00C7934F, 0x00C92C0A, 0x00CAC4C5 -}; - -#define CLAMP(x) ((x < 0) ? 0 : ((x > 255) ? 255 : x)) -#define SWAP(x,y) { x ^= y; y ^= x; x ^= y; } -#define VIDEO_MEM _MPEG_VIDEO_MEM_BASE -#define VIDEO_SIZE _MPEG_VIDEO_MEM_SIZE -#define WIDTH_OFF (VID_USER_MEM_BASE + 0x0100) -#define HEIGHT_OFF (VID_USER_MEM_BASE + 0x0102) -#define GFXFB_MEM _GFX_FB_MEM_BASE -#define GFXFB_SIZE _GFX_FB_MEM_SIZE -/* TODO: aspect ratio correction and PIP */ -bool cVideo::GetScreenImage(unsigned char * &video, int &xres, int &yres, bool get_video, bool get_osd, bool /*scale_to_video*/) -{ - hal_info("%s: get_video: %d get_osd: %d\n", __func__, get_video, get_osd); - uint8_t *map; - int mfd = open("/dev/mem", O_RDWR); - if (mfd < 0) { - hal_info("%s: cannot open open /dev/mem (%m)\n", __func__); - return false; - } - /* this hints at incorrect usage */ - if (video != NULL) - hal_info("%s: WARNING, video != NULL?\n", __func__); - - if (get_video) - { - map = (uint8_t *)mmap(NULL, VIDEO_SIZE, PROT_READ, MAP_SHARED, mfd, VIDEO_MEM); - if (map == MAP_FAILED) { - hal_info("%s: cannot mmap /dev/mem vor VIDEO (%m)\n", __func__); - close(mfd); - return false; - } - uint16_t w = *(uint16_t *)(map + WIDTH_OFF); - uint16_t h = *(uint16_t *)(map + HEIGHT_OFF); - if (w > 720 || h > 576) { - hal_info("%s: unhandled resolution %dx%d, is the tuner locked?\n", __func__, w, h); - munmap(map, VIDEO_SIZE); - close(mfd); - return false; - } - uint8_t *luma, *chroma; - int needmem = w * h * 5 / 4; /* chroma is 1/4 in size of luma */ - int lumasize = w * h; - int chromasize = needmem - lumasize; - uint8_t *buf = (uint8_t *)malloc(needmem); - if (!buf) { - hal_info("%s: cannot allocate %d bytes (%m)\n", __func__, needmem); - munmap(map, VIDEO_SIZE); - close(mfd); - return false; - } - /* luma is at the beginning of the buffer */ - memcpy(buf, map, lumasize); - /* it looks like the chroma plane is always 720*576 bytes offset to the luma plane */ - memcpy(buf + lumasize, map + 720 * 576, chromasize); - /* release the video buffer */ - munmap(map, VIDEO_SIZE); - - if (get_osd) - { /* in this case, the framebuffer determines the output resolution */ - xres = 720; - yres = 576; - } - else - { - xres = w; - yres = h; - } - video = (unsigned char *)malloc(xres * yres * 4); - if (!video) { - hal_info("%s: cannot allocate %d bytes for video buffer (%m)\n", __func__, yres * yres * 4); - free(buf); - close(mfd); - return false; - } - - luma = buf; - chroma = buf + lumasize; - - int Y, U, V, y, x, out1, pos, RU, GU, GV, BV, rgbstride, i; - - // yuv2rgb conversion (4:2:0) - hal_info("%s: converting Video from YUV to RGB color space\n", __func__); - out1 = pos = 0; - rgbstride = w * 4; - - for (y = h; y != 0; y -= 2) - { - for (x = w; x != 0; x -= 4) - { - U = *chroma++; - V = *chroma++; - RU = yuv2rgbtable_ru[U]; // use lookup tables to speedup the whole thing - GU = yuv2rgbtable_gu[U]; - GV = yuv2rgbtable_gv[V]; - BV = yuv2rgbtable_bv[V]; - // now we do 8 pixels on each iteration this is more code but much faster - for (i = 0; i < 4; i++) - { - Y = yuv2rgbtable_y[luma[pos]]; - video[out1 ] = CLAMP((Y + RU) >> 16); - video[out1 + 1] = CLAMP((Y - GV - GU) >> 16); - video[out1 + 2] = CLAMP((Y + BV) >> 16); - video[out1 + 3] = 0xff; - - Y = yuv2rgbtable_y[luma[w + pos]]; - video[out1 + rgbstride] = CLAMP((Y + RU) >> 16); - video[out1 + 1 + rgbstride] = CLAMP((Y - GV - GU) >> 16); - video[out1 + 2 + rgbstride] = CLAMP((Y + BV) >> 16); - video[out1 + 3 + rgbstride] = 0xff; - - pos++; - out1 += 4; - } - } - out1 += rgbstride; - pos += w; - } - if (get_osd && (w < xres || h < yres)) - { - /* most trivial scaling algorithm: - * - no smoothing/antialiasing or similar - * - only upscaling - * more or less just memcpy - * works "backwards" (from bottom right up left), - * so that no extra buffer is needed */ - int j, k; - uint32_t *v = (uint32_t *)video; /* int pointer to the video buffer */ - uint32_t *srcline; /* the start of the current line (unscaled) */ - uint32_t *dst = v + xres * yres; /* the current scaled pixel */ - for (j = yres -1 ; j >= 0; j--) - { - srcline = v + (((j * h) / yres) * w); - for (k = xres - 1; k >= 0; k--) { - dst--; - *dst = *(srcline + ((k * w) / xres)); - } - } - } - hal_info("%s: Video-Size: %d x %d\n", __func__, xres, yres); - free(buf); - } - if (get_osd) - { - if (! get_video) - { - /* we don't use other framebuffer resolutions */ - xres = 720; - yres = 576; - video = (unsigned char *)calloc(xres * yres, 4); - if (!video) - { - hal_info("%s: cannot allocate %d bytes for video buffer (%m)\n", __func__, yres * yres * 4); - close(mfd); - return false; - } - } - /* we don't need the framebufferdevice, we know where the FB is located */ - map = (uint8_t *)mmap(NULL, GFXFB_SIZE, PROT_READ, MAP_SHARED, mfd, GFXFB_MEM); - if (map == MAP_FAILED) { - hal_info("%s: cannot mmap /dev/mem for GFXFB (%m)\n", __func__); - close(mfd); - return false; - } - unsigned int i, r, g, b, a, a2; - uint8_t *p = map; - uint8_t *q = video; - for (i = xres * yres; i != 0; i--) - { - a = *p++; - r = *p++; - g = *p++; - b = *p++; - a2 = 0xff - a; - /* blue */ - *q = ((*q * a2 ) + (b * a)) >> 8; - q++; - /* green */ - *q = ((*q * a2 ) + (g * a)) >> 8; - q++; - /* red */ - *q = ((*q * a2 ) + (r * a)) >> 8; - q++; - q++; /* skip alpha byte */ - } - munmap(map, GFXFB_SIZE); - } - close(mfd); - return true; -} - -void cVideo::SetDemux(cDemux *) -{ - hal_debug("%s: not implemented yet\n", __func__); -} diff --git a/libtriple/video_td.h b/libtriple/video_td.h deleted file mode 100644 index 4c0e032..0000000 --- a/libtriple/video_td.h +++ /dev/null @@ -1,196 +0,0 @@ -#ifndef __VIDEO_TD_H__ -#define __VIDEO_TD_H__ - -#include -#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__