mirror of
https://github.com/tuxbox-neutrino/libstb-hal.git
synced 2025-08-26 15:02:58 +02:00
- AZBOX: libazbox deleted
This commit is contained in:
@@ -18,12 +18,6 @@ libstb_hal_la_LIBADD += \
|
|||||||
libtriple/libtriple.la
|
libtriple/libtriple.la
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if BOXTYPE_AZBOX
|
|
||||||
SUBDIRS += libazbox
|
|
||||||
libstb_hal_la_LIBADD += \
|
|
||||||
libazbox/libazbox.la
|
|
||||||
endif
|
|
||||||
|
|
||||||
if BOXTYPE_GENERIC
|
if BOXTYPE_GENERIC
|
||||||
if BOXMODEL_RASPI
|
if BOXMODEL_RASPI
|
||||||
SUBDIRS += libraspi
|
SUBDIRS += libraspi
|
||||||
|
@@ -75,9 +75,9 @@ AC_SYS_LARGEFILE
|
|||||||
|
|
||||||
AC_DEFUN([TUXBOX_BOXTYPE], [
|
AC_DEFUN([TUXBOX_BOXTYPE], [
|
||||||
AC_ARG_WITH(boxtype,
|
AC_ARG_WITH(boxtype,
|
||||||
AS_HELP_STRING([--with-boxtype], [valid values: generic, azbox, tripledragon, spark, duckbox, armbox, mipsbox]),
|
AS_HELP_STRING([--with-boxtype], [valid values: generic, tripledragon, spark, duckbox, armbox, mipsbox]),
|
||||||
[case "${withval}" in
|
[case "${withval}" in
|
||||||
generic|azbox|tripledragon|spark|duckbox|armbox|mipsbox)
|
generic|tripledragon|spark|duckbox|armbox|mipsbox)
|
||||||
BOXTYPE="$withval"
|
BOXTYPE="$withval"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
@@ -138,7 +138,6 @@ AC_SUBST(BOXTYPE)
|
|||||||
AC_SUBST(BOXMODEL)
|
AC_SUBST(BOXMODEL)
|
||||||
|
|
||||||
AM_CONDITIONAL(BOXTYPE_GENERIC, test "$BOXTYPE" = "generic")
|
AM_CONDITIONAL(BOXTYPE_GENERIC, test "$BOXTYPE" = "generic")
|
||||||
AM_CONDITIONAL(BOXTYPE_AZBOX, test "$BOXTYPE" = "azbox")
|
|
||||||
AM_CONDITIONAL(BOXTYPE_TRIPLE, test "$BOXTYPE" = "tripledragon")
|
AM_CONDITIONAL(BOXTYPE_TRIPLE, test "$BOXTYPE" = "tripledragon")
|
||||||
AM_CONDITIONAL(BOXTYPE_SPARK, test "$BOXTYPE" = "spark")
|
AM_CONDITIONAL(BOXTYPE_SPARK, test "$BOXTYPE" = "spark")
|
||||||
AM_CONDITIONAL(BOXTYPE_DUCKBOX, test "$BOXTYPE" = "duckbox")
|
AM_CONDITIONAL(BOXTYPE_DUCKBOX, test "$BOXTYPE" = "duckbox")
|
||||||
@@ -203,8 +202,6 @@ AM_CONDITIONAL(BOXMODEL_VUDUO, test "$BOXMODEL" = "vuduo")
|
|||||||
|
|
||||||
if test "$BOXTYPE" = "generic"; then
|
if test "$BOXTYPE" = "generic"; then
|
||||||
AC_DEFINE(HAVE_GENERIC_HARDWARE, 1, [building for a generic device like a standard PC])
|
AC_DEFINE(HAVE_GENERIC_HARDWARE, 1, [building for a generic device like a standard PC])
|
||||||
elif test "$BOXTYPE" = "azbox"; then
|
|
||||||
AC_DEFINE(HAVE_AZBOX_HARDWARE, 1, [building for an azbox])
|
|
||||||
elif test "$BOXTYPE" = "tripledragon"; then
|
elif test "$BOXTYPE" = "tripledragon"; then
|
||||||
AC_DEFINE(HAVE_TRIPLEDRAGON, 1, [building for a tripledragon])
|
AC_DEFINE(HAVE_TRIPLEDRAGON, 1, [building for a tripledragon])
|
||||||
elif test "$BOXTYPE" = "spark"; then
|
elif test "$BOXTYPE" = "spark"; then
|
||||||
|
@@ -108,7 +108,6 @@ Makefile
|
|||||||
common/Makefile
|
common/Makefile
|
||||||
libmipsbox/Makefile
|
libmipsbox/Makefile
|
||||||
libarmbox/Makefile
|
libarmbox/Makefile
|
||||||
libazbox/Makefile
|
|
||||||
libduckbox/Makefile
|
libduckbox/Makefile
|
||||||
libdvbci/Makefile
|
libdvbci/Makefile
|
||||||
libeplayer3/Makefile
|
libeplayer3/Makefile
|
||||||
|
@@ -11,8 +11,6 @@
|
|||||||
#include "../libarmbox/audio_lib.h"
|
#include "../libarmbox/audio_lib.h"
|
||||||
#elif HAVE_MIPS_HARDWARE
|
#elif HAVE_MIPS_HARDWARE
|
||||||
#include "../libmipsbox/audio_lib.h"
|
#include "../libmipsbox/audio_lib.h"
|
||||||
#elif HAVE_AZBOX_HARDWARE
|
|
||||||
#include "../libazbox/audio_lib.h"
|
|
||||||
#elif HAVE_GENERIC_HARDWARE
|
#elif HAVE_GENERIC_HARDWARE
|
||||||
#if BOXMODEL_RASPI
|
#if BOXMODEL_RASPI
|
||||||
#include "../libraspi/audio_lib.h"
|
#include "../libraspi/audio_lib.h"
|
||||||
|
@@ -17,8 +17,6 @@
|
|||||||
#endif
|
#endif
|
||||||
#elif HAVE_MIPS_HARDWARE
|
#elif HAVE_MIPS_HARDWARE
|
||||||
#include "../libmipsbox/playback_libeplayer3.h"
|
#include "../libmipsbox/playback_libeplayer3.h"
|
||||||
#elif HAVE_AZBOX_HARDWARE
|
|
||||||
#include "../libazbox/playback_lib.h"
|
|
||||||
#elif HAVE_GENERIC_HARDWARE
|
#elif HAVE_GENERIC_HARDWARE
|
||||||
#if BOXMODEL_RASPI
|
#if BOXMODEL_RASPI
|
||||||
#include "../libraspi/playback_lib.h"
|
#include "../libraspi/playback_lib.h"
|
||||||
|
@@ -9,8 +9,6 @@
|
|||||||
#include "../libarmbox/record_lib.h"
|
#include "../libarmbox/record_lib.h"
|
||||||
#elif HAVE_MIPS_HARDWARE
|
#elif HAVE_MIPS_HARDWARE
|
||||||
#include "../libmipsbox/record_lib.h"
|
#include "../libmipsbox/record_lib.h"
|
||||||
#elif HAVE_AZBOX_HARDWARE
|
|
||||||
#include "../libazbox/record_lib.h"
|
|
||||||
#elif HAVE_GENERIC_HARDWARE
|
#elif HAVE_GENERIC_HARDWARE
|
||||||
#if BOXMODEL_RASPI
|
#if BOXMODEL_RASPI
|
||||||
#include "../libraspi/record_lib.h"
|
#include "../libraspi/record_lib.h"
|
||||||
|
@@ -11,8 +11,6 @@
|
|||||||
#elif HAVE_MIPS_HARDWARE
|
#elif HAVE_MIPS_HARDWARE
|
||||||
#include "../libmipsbox/video_lib.h"
|
#include "../libmipsbox/video_lib.h"
|
||||||
#include "../libmipsbox/hdmi_cec.h"
|
#include "../libmipsbox/hdmi_cec.h"
|
||||||
#elif HAVE_AZBOX_HARDWARE
|
|
||||||
#include "../libazbox/video_lib.h"
|
|
||||||
#elif HAVE_GENERIC_HARDWARE
|
#elif HAVE_GENERIC_HARDWARE
|
||||||
#if BOXMODEL_RASPI
|
#if BOXMODEL_RASPI
|
||||||
#include "../libraspi/video_lib.h"
|
#include "../libraspi/video_lib.h"
|
||||||
|
@@ -1,18 +0,0 @@
|
|||||||
noinst_LTLIBRARIES = libazbox.la
|
|
||||||
|
|
||||||
AM_CPPFLAGS = \
|
|
||||||
-I$(top_srcdir)/common \
|
|
||||||
-I$(top_srcdir)/include
|
|
||||||
|
|
||||||
AM_CXXFLAGS = -fno-rtti -fno-exceptions -fno-strict-aliasing
|
|
||||||
AM_LDFLAGS = -lpthread
|
|
||||||
|
|
||||||
libazbox_la_SOURCES = \
|
|
||||||
hardware_caps.c \
|
|
||||||
dmx.cpp \
|
|
||||||
video.cpp \
|
|
||||||
audio.cpp \
|
|
||||||
init.cpp \
|
|
||||||
playback.cpp \
|
|
||||||
record.cpp
|
|
||||||
|
|
@@ -1,398 +0,0 @@
|
|||||||
#include <cstdio>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
|
||||||
#include <sys/fcntl.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <linux/dvb/audio.h>
|
|
||||||
|
|
||||||
#include <proc_tools.h>
|
|
||||||
|
|
||||||
#include "audio_lib.h"
|
|
||||||
#include "hal_debug.h"
|
|
||||||
|
|
||||||
#define AUDIO_DEVICE "/dev/dvb/adapter0/audio0"
|
|
||||||
#define hal_debug(args...) _hal_debug(HAL_DEBUG_AUDIO, this, args)
|
|
||||||
#define hal_info(args...) _hal_info(HAL_DEBUG_AUDIO, this, args)
|
|
||||||
|
|
||||||
#include <linux/soundcard.h>
|
|
||||||
|
|
||||||
cAudio * audioDecoder = NULL;
|
|
||||||
|
|
||||||
cAudio::cAudio(void *, void *, void *)
|
|
||||||
{
|
|
||||||
fd = -1;
|
|
||||||
clipfd = -1;
|
|
||||||
mixer_fd = -1;
|
|
||||||
openDevice();
|
|
||||||
Muted = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
cAudio::~cAudio(void)
|
|
||||||
{
|
|
||||||
closeDevice();
|
|
||||||
}
|
|
||||||
|
|
||||||
void cAudio::openDevice(void)
|
|
||||||
{
|
|
||||||
hal_debug("%s\n", __func__);
|
|
||||||
if (fd < 0)
|
|
||||||
{
|
|
||||||
if ((fd = open(AUDIO_DEVICE, O_RDONLY|O_CLOEXEC)) < 0)
|
|
||||||
hal_info("openDevice: open failed (%m)\n");
|
|
||||||
do_mute(true, false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
hal_info("openDevice: already open (fd = %d)\n", fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cAudio::closeDevice(void)
|
|
||||||
{
|
|
||||||
hal_debug("%s\n", __func__);
|
|
||||||
ioctl(fd, AUDIO_CONTINUE); /* enigma2 also does CONTINUE before close... */
|
|
||||||
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", __func__, enable, remember);
|
|
||||||
|
|
||||||
if (remember)
|
|
||||||
Muted = enable;
|
|
||||||
#if 0
|
|
||||||
/* does not work? */
|
|
||||||
if (ioctl(fd, AUDIO_SET_MUTE, enable) < 0 )
|
|
||||||
hal_info("%s: AUDIO_SET_MUTE failed (%m)\n", __func__);
|
|
||||||
#else
|
|
||||||
char s[2] = { 0, 0 };
|
|
||||||
s[0] = '0' + (int)enable;
|
|
||||||
proc_put("/proc/stb/audio/j1_mute", s, 2);
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int map_volume(const int volume)
|
|
||||||
{
|
|
||||||
unsigned char vol = volume;
|
|
||||||
if (vol > 100)
|
|
||||||
vol = 100;
|
|
||||||
|
|
||||||
vol = 63 - vol * 63 / 100;
|
|
||||||
return vol;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int cAudio::setVolume(unsigned int left, unsigned int right)
|
|
||||||
{
|
|
||||||
hal_debug("%s(%d, %d)\n", __func__, left, right);
|
|
||||||
|
|
||||||
volume = (left + right) / 2;
|
|
||||||
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;
|
|
||||||
int 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
audio_mixer_t mixer;
|
|
||||||
mixer.volume_left = map_volume(left);
|
|
||||||
mixer.volume_right = map_volume(right);
|
|
||||||
|
|
||||||
if (ioctl(fd, AUDIO_SET_MIXER, &mixer) < 0)
|
|
||||||
hal_info("%s: AUDIO_SET_MIXER failed (%m)\n", __func__);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cAudio::Start(void)
|
|
||||||
{
|
|
||||||
hal_debug("%s\n", __func__);
|
|
||||||
int ret;
|
|
||||||
ioctl(fd, AUDIO_CONTINUE);
|
|
||||||
ret = ioctl(fd, AUDIO_PLAY);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cAudio::Stop(void)
|
|
||||||
{
|
|
||||||
hal_debug("%s\n", __func__);
|
|
||||||
ioctl(fd, AUDIO_STOP);
|
|
||||||
ioctl(fd, AUDIO_CONTINUE); /* no idea why we have to stop and then continue => enigma2 does it, too */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cAudio::Pause(bool /*Pcm*/)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
void cAudio::SetSyncMode(AVSYNC_TYPE Mode)
|
|
||||||
{
|
|
||||||
hal_debug("%s %d\n", __func__, Mode);
|
|
||||||
ioctl(fd, AUDIO_SET_AV_SYNC, Mode);
|
|
||||||
};
|
|
||||||
|
|
||||||
//AUDIO_ENCODING_AC3
|
|
||||||
#define AUDIO_STREAMTYPE_AC3 0
|
|
||||||
//AUDIO_ENCODING_MPEG2
|
|
||||||
#define AUDIO_STREAMTYPE_MPEG 1
|
|
||||||
//AUDIO_ENCODING_DTS
|
|
||||||
#define AUDIO_STREAMTYPE_DTS 2
|
|
||||||
|
|
||||||
#define AUDIO_ENCODING_LPCM 2
|
|
||||||
#define AUDIO_ENCODING_LPCMA 11
|
|
||||||
void cAudio::SetStreamType(AUDIO_FORMAT type)
|
|
||||||
{
|
|
||||||
int bypass = AUDIO_STREAMTYPE_MPEG;
|
|
||||||
hal_debug("%s %d\n", __func__, type);
|
|
||||||
StreamType = type;
|
|
||||||
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case AUDIO_FMT_DOLBY_DIGITAL:
|
|
||||||
bypass = AUDIO_STREAMTYPE_AC3;
|
|
||||||
break;
|
|
||||||
case AUDIO_FMT_DTS:
|
|
||||||
bypass = AUDIO_STREAMTYPE_DTS;
|
|
||||||
break;
|
|
||||||
case AUDIO_FMT_MPEG:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Normaly the encoding should be set using AUDIO_SET_ENCODING
|
|
||||||
// But as we implemented the behavior to bypass (cause of e2) this is correct here
|
|
||||||
if (ioctl(fd, AUDIO_SET_BYPASS_MODE, bypass) < 0)
|
|
||||||
hal_info("%s: AUDIO_SET_BYPASS_MODE failed (%m)\n", __func__);
|
|
||||||
};
|
|
||||||
|
|
||||||
int cAudio::setChannel(int 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 OSS device
|
|
||||||
* Example:
|
|
||||||
* modprobe snd-usb-audio
|
|
||||||
* export DSP_DEVICE=/dev/sound/dsp2
|
|
||||||
* export MIX_DEVICE=/dev/sound/mixer2
|
|
||||||
* 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/dsp1\n", __func__, dsp_dev);
|
|
||||||
dsp_dev = "/dev/dsp1";
|
|
||||||
}
|
|
||||||
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|O_CLOEXEC);
|
|
||||||
if (clipfd < 0) {
|
|
||||||
hal_info("%s open %s: %m\n", dsp_dev, __FUNCTION__);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
/* 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|O_CLOEXEC);
|
|
||||||
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, (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__);
|
|
||||||
type = 0;
|
|
||||||
layer = 0;
|
|
||||||
freq = 0;
|
|
||||||
bitrate = 0;
|
|
||||||
mode = 0;
|
|
||||||
#if 0
|
|
||||||
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);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
void cAudio::SetSRS(int /*iq_enable*/, int /*nmgr_enable*/, int /*iq_mode*/, int /*iq_level*/)
|
|
||||||
{
|
|
||||||
hal_debug("%s\n", __FUNCTION__);
|
|
||||||
};
|
|
||||||
|
|
||||||
void cAudio::SetHdmiDD(bool enable)
|
|
||||||
{
|
|
||||||
hal_debug("%s %d\n", __func__, enable);
|
|
||||||
};
|
|
||||||
|
|
||||||
void cAudio::SetSpdifDD(bool enable)
|
|
||||||
{
|
|
||||||
hal_debug("%s %d\n", __func__, enable);
|
|
||||||
setBypassMode(!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);
|
|
||||||
};
|
|
||||||
|
|
||||||
#define AUDIO_BYPASS_ON 0
|
|
||||||
#define AUDIO_BYPASS_OFF 1
|
|
||||||
void cAudio::setBypassMode(bool disable)
|
|
||||||
{
|
|
||||||
hal_debug("%s %d\n", __func__, disable);
|
|
||||||
int mode = disable ? AUDIO_BYPASS_OFF : AUDIO_BYPASS_ON;
|
|
||||||
if (ioctl(fd, AUDIO_SET_BYPASS_MODE, mode) < 0)
|
|
||||||
hal_info("%s AUDIO_SET_BYPASS_MODE %d: %m\n", __func__, mode);
|
|
||||||
return;
|
|
||||||
}
|
|
@@ -1,97 +0,0 @@
|
|||||||
/* public header file */
|
|
||||||
|
|
||||||
#ifndef __AUDIO_LIB_H__
|
|
||||||
#define __AUDIO_LIB_H__
|
|
||||||
|
|
||||||
#include "../common/cs_types.h"
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
AUDIO_SYNC_WITH_PTS,
|
|
||||||
AUDIO_NO_SYNC,
|
|
||||||
AUDIO_SYNC_AUDIO_MASTER
|
|
||||||
} AUDIO_SYNC_MODE;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
HDMI_ENCODED_OFF,
|
|
||||||
HDMI_ENCODED_AUTO,
|
|
||||||
HDMI_ENCODED_FORCED
|
|
||||||
} HDMI_ENCODED_MODE;
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
AUDIO_FMT_AUTO = 0,
|
|
||||||
AUDIO_FMT_MPEG,
|
|
||||||
AUDIO_FMT_MP3,
|
|
||||||
AUDIO_FMT_DOLBY_DIGITAL,
|
|
||||||
AUDIO_FMT_BASIC = AUDIO_FMT_DOLBY_DIGITAL,
|
|
||||||
AUDIO_FMT_AAC,
|
|
||||||
AUDIO_FMT_AAC_PLUS,
|
|
||||||
AUDIO_FMT_DD_PLUS,
|
|
||||||
AUDIO_FMT_DTS,
|
|
||||||
AUDIO_FMT_AVS,
|
|
||||||
AUDIO_FMT_MLP,
|
|
||||||
AUDIO_FMT_WMA,
|
|
||||||
AUDIO_FMT_MPG1, // TD only. For Movieplayer / cPlayback
|
|
||||||
AUDIO_FMT_ADVANCED = AUDIO_FMT_MLP
|
|
||||||
} AUDIO_FORMAT;
|
|
||||||
|
|
||||||
class cAudio
|
|
||||||
{
|
|
||||||
friend class cPlayback;
|
|
||||||
private:
|
|
||||||
int fd;
|
|
||||||
bool Muted;
|
|
||||||
|
|
||||||
int clipfd; /* for pcm playback */
|
|
||||||
int mixer_fd; /* if we are using the OSS mixer */
|
|
||||||
int mixer_num; /* oss mixer to use, if any */
|
|
||||||
|
|
||||||
AUDIO_FORMAT StreamType;
|
|
||||||
AUDIO_SYNC_MODE SyncMode;
|
|
||||||
bool started;
|
|
||||||
|
|
||||||
int volume;
|
|
||||||
|
|
||||||
void openDevice(void);
|
|
||||||
void closeDevice(void);
|
|
||||||
|
|
||||||
int do_mute(bool enable, bool remember);
|
|
||||||
void setBypassMode(bool disable);
|
|
||||||
public:
|
|
||||||
/* construct & destruct */
|
|
||||||
cAudio(void *, void *, void *);
|
|
||||||
~cAudio(void);
|
|
||||||
|
|
||||||
void *GetHandle() { return NULL; };
|
|
||||||
/* shut up */
|
|
||||||
int mute(bool remember = true) { return do_mute(true, remember); };
|
|
||||||
int unmute(bool remember = true) { return do_mute(false, remember); };
|
|
||||||
|
|
||||||
/* volume, min = 0, max = 255 */
|
|
||||||
int setVolume(unsigned int left, unsigned int right);
|
|
||||||
int getVolume(void) { return volume;}
|
|
||||||
bool getMuteStatus(void) { return Muted; };
|
|
||||||
|
|
||||||
/* start and stop audio */
|
|
||||||
int Start(void);
|
|
||||||
int Stop(void);
|
|
||||||
bool Pause(bool Pcm = true);
|
|
||||||
void SetStreamType(AUDIO_FORMAT type);
|
|
||||||
void SetSyncMode(AVSYNC_TYPE Mode);
|
|
||||||
|
|
||||||
/* select channels */
|
|
||||||
int setChannel(int channel);
|
|
||||||
int PrepareClipPlay(int uNoOfChannels, int uSampleRate, int uBitsPerSample, int bLittleEndian);
|
|
||||||
int WriteClip(unsigned char * buffer, int size);
|
|
||||||
int StopClip();
|
|
||||||
void getAudioInfo(int &type, int &layer, int& freq, int &bitrate, int &mode);
|
|
||||||
void SetSRS(int iq_enable, int nmgr_enable, int iq_mode, int iq_level);
|
|
||||||
bool IsHdmiDDSupported();
|
|
||||||
void SetHdmiDD(bool enable);
|
|
||||||
void SetSpdifDD(bool enable);
|
|
||||||
void ScheduleMute(bool On);
|
|
||||||
void EnableAnalogOut(bool enable);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // __AUDIO_LIB_H__
|
|
519
libazbox/dmx.cpp
519
libazbox/dmx.cpp
@@ -1,519 +0,0 @@
|
|||||||
/*
|
|
||||||
* cDemux implementation for azbox receivers (tested on azbox me and minime)
|
|
||||||
*
|
|
||||||
* derived from libtriple/dmx_td.cpp
|
|
||||||
*
|
|
||||||
* (C) 2010-2013 Stefan Seyfried
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <poll.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <string>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include "dmx_hal.h"
|
|
||||||
#include "hal_debug.h"
|
|
||||||
|
|
||||||
#include "video_lib.h"
|
|
||||||
/* needed for getSTC... */
|
|
||||||
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 hal_info_c(args...) _hal_info(HAL_DEBUG_DEMUX, NULL, 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. for now only demux0 is used */
|
|
||||||
static const char *devname[] = {
|
|
||||||
"/dev/dvb/adapter0/demux0",
|
|
||||||
"/dev/dvb/adapter0/demux0",
|
|
||||||
"/dev/dvb/adapter0/demux0"
|
|
||||||
};
|
|
||||||
|
|
||||||
/* uuuugly */
|
|
||||||
static int dmx_tp_count = 0;
|
|
||||||
#define MAX_TS_COUNT 8
|
|
||||||
|
|
||||||
cDemux::cDemux(int n)
|
|
||||||
{
|
|
||||||
if (n < 0 || n > 2)
|
|
||||||
{
|
|
||||||
hal_info("%s ERROR: n invalid (%d)\n", __FUNCTION__, n);
|
|
||||||
num = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
num = n;
|
|
||||||
fd = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cDemux::~cDemux()
|
|
||||||
{
|
|
||||||
hal_debug("%s #%d fd: %d\n", __FUNCTION__, num, fd);
|
|
||||||
Close();
|
|
||||||
/* in zapit.cpp, videoDemux is deleted after videoDecoder
|
|
||||||
* in the video watchdog, we access videoDecoder
|
|
||||||
* the thread still runs after videoDecoder has been deleted
|
|
||||||
* => set videoDecoder to NULL here to make the check in the
|
|
||||||
* watchdog thread pick this up.
|
|
||||||
* This is ugly, but it saves me from changing neutrino
|
|
||||||
*
|
|
||||||
* if the delete order in neutrino will ever be changed, this
|
|
||||||
* will blow up badly :-(
|
|
||||||
*/
|
|
||||||
if (dmx_type == DMX_VIDEO_CHANNEL)
|
|
||||||
videoDecoder = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cDemux::Open(DMX_CHANNEL_TYPE pes_type, void * /*hVideoBuffer*/, int uBufferSize)
|
|
||||||
{
|
|
||||||
int devnum = num;
|
|
||||||
int flags = O_RDWR|O_CLOEXEC;
|
|
||||||
if (fd > -1)
|
|
||||||
hal_info("%s FD ALREADY OPENED? fd = %d\n", __FUNCTION__, fd);
|
|
||||||
|
|
||||||
if (pes_type != DMX_PSI_CHANNEL)
|
|
||||||
flags |= O_NONBLOCK;
|
|
||||||
|
|
||||||
fd = open(devname[devnum], flags);
|
|
||||||
if (fd < 0)
|
|
||||||
{
|
|
||||||
hal_info("%s %s: %m\n", __FUNCTION__, devname[devnum]);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
hal_debug("%s #%d pes_type: %s(%d), uBufferSize: %d fd: %d\n", __func__,
|
|
||||||
num, DMX_T[pes_type], pes_type, uBufferSize, fd);
|
|
||||||
|
|
||||||
dmx_type = pes_type;
|
|
||||||
#if 0
|
|
||||||
if (!pesfds.empty())
|
|
||||||
{
|
|
||||||
hal_info("%s ERROR! pesfds not empty!\n", __FUNCTION__); /* TODO: error handling */
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int n = DMX_SOURCE_FRONT0;
|
|
||||||
if (ioctl(fd, DMX_SET_SOURCE, &n) < 0)
|
|
||||||
hal_info("%s DMX_SET_SOURCE failed!\n", __func__);
|
|
||||||
#endif
|
|
||||||
if (uBufferSize > 0)
|
|
||||||
{
|
|
||||||
/* probably uBufferSize == 0 means "use default size". TODO: find a reasonable default */
|
|
||||||
if (ioctl(fd, DMX_SET_BUFFER_SIZE, uBufferSize) < 0)
|
|
||||||
hal_info("%s DMX_SET_BUFFER_SIZE failed (%m)\n", __func__);
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
pesfds.clear();
|
|
||||||
ioctl(fd, DMX_STOP);
|
|
||||||
close(fd);
|
|
||||||
fd = -1;
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
hal_debug("%s #%d fd: %d type: %s\n", __func__, num, fd, DMX_T[dmx_type]);
|
|
||||||
if (fd < 0)
|
|
||||||
{
|
|
||||||
hal_info("%s #%d: not open!\n", __FUNCTION__, num);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
ioctl(fd, DMX_START);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cDemux::Stop(void)
|
|
||||||
{
|
|
||||||
hal_debug("%s #%d fd: %d type: %s\n", __func__, num, fd, DMX_T[dmx_type]);
|
|
||||||
if (fd < 0)
|
|
||||||
{
|
|
||||||
hal_info("%s #%d: not open!\n", __FUNCTION__, num);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
ioctl(fd, DMX_STOP);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cDemux::Read(unsigned char *buff, int len, int timeout)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
if (len != 4095 && timeout != 100)
|
|
||||||
fprintf(stderr, "cDemux::%s #%d fd: %d type: %s len: %d timeout: %d\n",
|
|
||||||
__FUNCTION__, num, fd, DMX_T[dmx_type], len, timeout);
|
|
||||||
#endif
|
|
||||||
int rc;
|
|
||||||
int to = timeout;
|
|
||||||
/* using a one-dimensional array seems to avoid strange segfaults / memory corruption?? */
|
|
||||||
struct pollfd ufds[1];
|
|
||||||
ufds[0].fd = fd;
|
|
||||||
ufds[0].events = POLLIN|POLLPRI|POLLERR;
|
|
||||||
ufds[0].revents = 0;
|
|
||||||
|
|
||||||
/* hack: if the frontend loses and regains lock, the demuxer often will not
|
|
||||||
* return from read(), so as a "emergency exit" for e.g. NIT scan, set a (long)
|
|
||||||
* timeout here */
|
|
||||||
if (dmx_type == DMX_PSI_CHANNEL && timeout <= 0)
|
|
||||||
to = 60 * 1000;
|
|
||||||
|
|
||||||
if (to > 0)
|
|
||||||
{
|
|
||||||
retry:
|
|
||||||
rc = ::poll(ufds, 1, to);
|
|
||||||
if (!rc)
|
|
||||||
{
|
|
||||||
if (timeout == 0) /* we took the emergency exit */
|
|
||||||
{
|
|
||||||
dmx_err("timed out for timeout=0!, %s", "", 0);
|
|
||||||
return -1; /* this timeout is an error */
|
|
||||||
}
|
|
||||||
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 0
|
|
||||||
if (ufds.revents & POLLERR) /* POLLERR means buffer error, i.e. buffer overflow */
|
|
||||||
{
|
|
||||||
dmx_err("received %s,", "POLLERR", ufds.revents);
|
|
||||||
/* this seems to happen sometimes at recording start, without bad effects */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (ufds[0].revents & POLLHUP) /* we get POLLHUP if e.g. a too big DMX_BUFFER_SIZE was set */
|
|
||||||
{
|
|
||||||
dmx_err("received %s,", "POLLHUP", ufds[0].revents);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (!(ufds[0].revents & POLLIN)) /* we requested POLLIN but did not get it? */
|
|
||||||
{
|
|
||||||
dmx_err("received %s, please report!", "POLLIN", ufds[0].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)
|
|
||||||
{
|
|
||||||
struct dmx_sct_filter_params s_flt;
|
|
||||||
memset(&s_flt, 0, sizeof(s_flt));
|
|
||||||
pid = _pid;
|
|
||||||
|
|
||||||
if (len > DMX_FILTER_SIZE)
|
|
||||||
{
|
|
||||||
hal_info("%s #%d: len too long: %d, DMX_FILTER_SIZE %d\n", __func__, num, len, DMX_FILTER_SIZE);
|
|
||||||
len = DMX_FILTER_SIZE;
|
|
||||||
}
|
|
||||||
s_flt.pid = pid;
|
|
||||||
s_flt.timeout = timeout;
|
|
||||||
flt = filter[0];
|
|
||||||
memcpy(s_flt.filter.filter, filter, len);
|
|
||||||
memcpy(s_flt.filter.mask, mask, len);
|
|
||||||
if (negmask != NULL)
|
|
||||||
memcpy(s_flt.filter.mode, negmask, len);
|
|
||||||
|
|
||||||
s_flt.flags = DMX_IMMEDIATE_START|DMX_CHECK_CRC;
|
|
||||||
|
|
||||||
int to = 0;
|
|
||||||
switch (filter[0]) {
|
|
||||||
case 0x00: /* program_association_section */
|
|
||||||
to = 2000;
|
|
||||||
break;
|
|
||||||
case 0x01: /* conditional_access_section */
|
|
||||||
to = 6000;
|
|
||||||
break;
|
|
||||||
case 0x02: /* program_map_section */
|
|
||||||
to = 1500;
|
|
||||||
break;
|
|
||||||
case 0x03: /* transport_stream_description_section */
|
|
||||||
to = 10000;
|
|
||||||
break;
|
|
||||||
/* 0x04 - 0x3F: reserved */
|
|
||||||
case 0x40: /* network_information_section - actual_network */
|
|
||||||
to = 10000;
|
|
||||||
break;
|
|
||||||
case 0x41: /* network_information_section - other_network */
|
|
||||||
to = 15000;
|
|
||||||
break;
|
|
||||||
case 0x42: /* service_description_section - actual_transport_stream */
|
|
||||||
to = 10000;
|
|
||||||
break;
|
|
||||||
/* 0x43 - 0x45: reserved for future use */
|
|
||||||
case 0x46: /* service_description_section - other_transport_stream */
|
|
||||||
to = 10000;
|
|
||||||
break;
|
|
||||||
/* 0x47 - 0x49: reserved for future use */
|
|
||||||
case 0x4A: /* bouquet_association_section */
|
|
||||||
to = 11000;
|
|
||||||
break;
|
|
||||||
/* 0x4B - 0x4D: reserved for future use */
|
|
||||||
case 0x4E: /* event_information_section - actual_transport_stream, present/following */
|
|
||||||
to = 2000;
|
|
||||||
break;
|
|
||||||
case 0x4F: /* event_information_section - other_transport_stream, present/following */
|
|
||||||
to = 10000;
|
|
||||||
break;
|
|
||||||
/* 0x50 - 0x5F: event_information_section - actual_transport_stream, schedule */
|
|
||||||
/* 0x60 - 0x6F: event_information_section - other_transport_stream, schedule */
|
|
||||||
case 0x70: /* time_date_section */
|
|
||||||
s_flt.flags &= ~DMX_CHECK_CRC; /* section has no CRC */
|
|
||||||
s_flt.flags |= DMX_ONESHOT;
|
|
||||||
//s_flt.pid = 0x0014;
|
|
||||||
to = 30000;
|
|
||||||
break;
|
|
||||||
case 0x71: /* running_status_section */
|
|
||||||
s_flt.flags &= ~DMX_CHECK_CRC; /* section has no CRC */
|
|
||||||
to = 0;
|
|
||||||
break;
|
|
||||||
case 0x72: /* stuffing_section */
|
|
||||||
s_flt.flags &= ~DMX_CHECK_CRC; /* section has no CRC */
|
|
||||||
to = 0;
|
|
||||||
break;
|
|
||||||
case 0x73: /* time_offset_section */
|
|
||||||
s_flt.flags |= DMX_ONESHOT;
|
|
||||||
//s_flt.pid = 0x0014;
|
|
||||||
to = 30000;
|
|
||||||
break;
|
|
||||||
/* 0x74 - 0x7D: reserved for future use */
|
|
||||||
case 0x7E: /* discontinuity_information_section */
|
|
||||||
s_flt.flags &= ~DMX_CHECK_CRC; /* section has no CRC */
|
|
||||||
to = 0;
|
|
||||||
break;
|
|
||||||
case 0x7F: /* selection_information_section */
|
|
||||||
to = 0;
|
|
||||||
break;
|
|
||||||
/* 0x80 - 0x8F: ca_message_section */
|
|
||||||
/* 0x90 - 0xFE: user defined */
|
|
||||||
/* 0xFF: reserved */
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
// return -1;
|
|
||||||
}
|
|
||||||
/* the negmask == NULL is a hack: the users of negmask are PMT-update
|
|
||||||
* and sectionsd EIT-Version change. And they really want no timeout
|
|
||||||
* if timeout == 0 instead of "default timeout" */
|
|
||||||
if (timeout == 0 && negmask == NULL)
|
|
||||||
s_flt.timeout = to;
|
|
||||||
|
|
||||||
hal_debug("%s #%d pid:0x%04hx fd:%d type:%s len:%d to:%d flags:%x flt[0]:%02x\n", __func__, num,
|
|
||||||
pid, fd, DMX_T[dmx_type], len, s_flt.timeout,s_flt.flags, s_flt.filter.filter[0]);
|
|
||||||
#if 0
|
|
||||||
fprintf(stderr,"filt: ");for(int i=0;i<DMX_FILTER_SIZE;i++)fprintf(stderr,"%02hhx ",s_flt.filter.filter[i]);fprintf(stderr,"\n");
|
|
||||||
fprintf(stderr,"mask: ");for(int i=0;i<DMX_FILTER_SIZE;i++)fprintf(stderr,"%02hhx ",s_flt.filter.mask [i]);fprintf(stderr,"\n");
|
|
||||||
fprintf(stderr,"mode: ");for(int i=0;i<DMX_FILTER_SIZE;i++)fprintf(stderr,"%02hhx ",s_flt.filter.mode [i]);fprintf(stderr,"\n");
|
|
||||||
#endif
|
|
||||||
ioctl (fd, DMX_STOP);
|
|
||||||
if (ioctl(fd, DMX_SET_FILTER, &s_flt) < 0)
|
|
||||||
return false;
|
|
||||||
ioctl(fd, DMX_START);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cDemux::pesFilter(const unsigned short _pid)
|
|
||||||
{
|
|
||||||
struct dmx_pes_filter_params 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]);
|
|
||||||
|
|
||||||
memset(&p_flt, 0, sizeof(p_flt));
|
|
||||||
p_flt.pid = pid;
|
|
||||||
p_flt.output = DMX_OUT_DECODER;
|
|
||||||
p_flt.input = DMX_IN_FRONTEND;
|
|
||||||
|
|
||||||
switch (dmx_type) {
|
|
||||||
case DMX_PCR_ONLY_CHANNEL:
|
|
||||||
p_flt.pes_type = DMX_PES_PCR;
|
|
||||||
break;
|
|
||||||
case DMX_AUDIO_CHANNEL:
|
|
||||||
p_flt.pes_type = DMX_PES_AUDIO;
|
|
||||||
break;
|
|
||||||
case DMX_VIDEO_CHANNEL:
|
|
||||||
p_flt.pes_type = DMX_PES_VIDEO;
|
|
||||||
break;
|
|
||||||
case DMX_PES_CHANNEL:
|
|
||||||
p_flt.pes_type = DMX_PES_OTHER;
|
|
||||||
p_flt.output = DMX_OUT_TAP;
|
|
||||||
break;
|
|
||||||
case DMX_TP_CHANNEL:
|
|
||||||
p_flt.pes_type = DMX_PES_OTHER;
|
|
||||||
p_flt.output = DMX_OUT_TSDEMUX_TAP;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
hal_info("%s #%d invalid dmx_type %d!\n", __func__, num, dmx_type);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return (ioctl(fd, DMX_SET_PES_FILTER, &p_flt) >= 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cDemux::SetSyncMode(AVSYNC_TYPE /*mode*/)
|
|
||||||
{
|
|
||||||
hal_debug("%s #%d\n", __FUNCTION__, num);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *cDemux::getBuffer()
|
|
||||||
{
|
|
||||||
hal_debug("%s #%d\n", __FUNCTION__, num);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *cDemux::getChannel()
|
|
||||||
{
|
|
||||||
hal_debug("%s #%d\n", __FUNCTION__, num);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cDemux::addPid(unsigned short Pid)
|
|
||||||
{
|
|
||||||
hal_debug("%s: pid 0x%04hx\n", __func__, Pid);
|
|
||||||
pes_pids pfd;
|
|
||||||
int ret;
|
|
||||||
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 (fd == -1)
|
|
||||||
hal_info("%s bucketfd not yet opened? pid=%hx\n", __FUNCTION__, Pid);
|
|
||||||
pfd.fd = fd; /* dummy */
|
|
||||||
pfd.pid = Pid;
|
|
||||||
pesfds.push_back(pfd);
|
|
||||||
ret = (ioctl(fd, DMX_ADD_PID, &Pid));
|
|
||||||
if (ret < 0)
|
|
||||||
hal_info("%s: DMX_ADD_PID (%m)\n", __func__);
|
|
||||||
return (ret != -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cDemux::removePid(unsigned short Pid)
|
|
||||||
{
|
|
||||||
if (dmx_type != DMX_TP_CHANNEL)
|
|
||||||
{
|
|
||||||
hal_info("%s pes_type %s not implemented yet! pid=%hx\n", __FUNCTION__, DMX_T[dmx_type], Pid);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (std::vector<pes_pids>::iterator i = pesfds.begin(); i != pesfds.end(); ++i)
|
|
||||||
{
|
|
||||||
if ((*i).pid == Pid) {
|
|
||||||
hal_debug("removePid: removing demux fd %d pid 0x%04x\n", fd, Pid);
|
|
||||||
if (ioctl(fd, DMX_REMOVE_PID, Pid) < 0)
|
|
||||||
hal_info("%s: (DMX_REMOVE_PID, 0x%04hx): %m\n", __func__, Pid);
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
/* apparently I can only get the PTS of the video decoder,
|
|
||||||
* but that's good enough for dvbsub */
|
|
||||||
hal_debug("%s #%d\n", __func__, num);
|
|
||||||
int64_t pts = 0;
|
|
||||||
if (videoDecoder)
|
|
||||||
pts = videoDecoder->GetPTS();
|
|
||||||
*STC = pts;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cDemux::SetSource(int unit, int source)
|
|
||||||
{
|
|
||||||
hal_info_c("%s(%d, %d): not implemented yet\n", __func__, unit, source);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cDemux::GetSource(int unit)
|
|
||||||
{
|
|
||||||
hal_info_c("%s(%d): not implemented yet\n", __func__, unit);
|
|
||||||
return 0;
|
|
||||||
}
|
|
@@ -1,83 +0,0 @@
|
|||||||
//Additional Azbox
|
|
||||||
enum key_command {
|
|
||||||
KEY_COMMAND_QUIT_ALL = 100,
|
|
||||||
KEY_COMMAND_QUIT,
|
|
||||||
KEY_COMMAND_PLAY,
|
|
||||||
KEY_COMMAND_PAUSE,
|
|
||||||
KEY_COMMAND_RESUME,
|
|
||||||
KEY_COMMAND_STOP,
|
|
||||||
KEY_COMMAND_SEEK_TO_TIME,
|
|
||||||
KEY_COMMAND_SEEK_TO_PERCENT,
|
|
||||||
KEY_COMMAND_NEXT_PICT,
|
|
||||||
KEY_COMMAND_FAST_FWD_ALL_FRAMES,
|
|
||||||
KEY_COMMAND_SLOW_FWD_ALL_FRAMES,
|
|
||||||
KEY_COMMAND_IFRAMES_FWD,
|
|
||||||
KEY_COMMAND_IFRAMES_BWD,
|
|
||||||
KEY_COMMAND_SILENT_FWD,
|
|
||||||
KEY_COMMAND_SILENT_BWD,
|
|
||||||
KEY_COMMAND_SWITCH_VIDEO,
|
|
||||||
KEY_COMMAND_SWITCH_AUDIO,
|
|
||||||
KEY_COMMAND_SWITCH_PROGRAM,
|
|
||||||
KEY_COMMAND_SWITCH_SUBS,
|
|
||||||
KEY_COMMAND_SWITCH_MULTICAST,
|
|
||||||
KEY_COMMAND_APPLY_AV_DELAY,
|
|
||||||
KEY_COMMAND_SUBS_CHANGE_DELAY,
|
|
||||||
KEY_COMMAND_SUBS_INCREASE_FONT_SIZE,
|
|
||||||
KEY_COMMAND_SUBS_DECREASE_FONT_SIZE,
|
|
||||||
KEY_COMMAND_SUBS_INCREASE_POS_Y,
|
|
||||||
KEY_COMMAND_SUBS_DECREASE_POS_Y,
|
|
||||||
KEY_COMMAND_SUBS_SWITCH_ENCODING,
|
|
||||||
KEY_COMMAND_SUBS_RESET_ALL,
|
|
||||||
KEY_COMMAND_SUBS_CHANGE_COLOR,
|
|
||||||
KEY_COMMAND_DEBUG,
|
|
||||||
KEY_COMMAND_PRINT_INFO,
|
|
||||||
KEY_COMMAND_FULL_SCREEN,
|
|
||||||
KEY_COMMAND_HALF_SCREEN,
|
|
||||||
KEY_COMMAND_INCREASE_SIZE,
|
|
||||||
KEY_COMMAND_DECREASE_SIZE,
|
|
||||||
KEY_COMMAND_MOVE_LEFT,
|
|
||||||
KEY_COMMAND_MOVE_RIGHT,
|
|
||||||
KEY_COMMAND_MOVE_TOP,
|
|
||||||
KEY_COMMAND_MOVE_BOTTOM,
|
|
||||||
KEY_COMMAND_NONLINEAR_WIDTH,
|
|
||||||
KEY_COMMAND_NONLINEAR_LEVEL,
|
|
||||||
KEY_COMMAND_SWITCH_SCALER,
|
|
||||||
KEY_COMMAND_HELP,
|
|
||||||
KEY_COMMAND_FAST_FWD_WITH_AUDIO,
|
|
||||||
KEY_COMMAND_SLOW_FWD_WITH_AUDIO,
|
|
||||||
KEY_COMMAND_PRINT_TXT,
|
|
||||||
SPECIAL_KEY_COMMAND_IFRAMES_FWD,
|
|
||||||
SPECIAL_KEY_COMMAND_IFRAMES_BWD,
|
|
||||||
SPECIAL_KEY_COMMAND_NEXT_AUDIO,
|
|
||||||
SPECIAL_KEY_COMMAND_NEXT_SUBS,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum custom_command {
|
|
||||||
CUSTOM_COMMAND_GETLENGTH = 200,
|
|
||||||
CUSTOM_COMMAND_GETPOSITION,
|
|
||||||
CUSTOM_COMMAND_AUDIOGETPOSITION,
|
|
||||||
CUSTOM_COMMAND_SEEK_RELATIVE_FWD,
|
|
||||||
CUSTOM_COMMAND_SEEK_RELATIVE_BWD,
|
|
||||||
CUSTOM_COMMAND_SUBS_COUNT,
|
|
||||||
CUSTOM_COMMAND_GET_SUB_BY_ID,
|
|
||||||
CUSTOM_COMMAND_AUDIO_COUNT,
|
|
||||||
CUSTOM_COMMAND_GET_AUDIO_BY_ID,
|
|
||||||
CUSTOM_COMMAND_AUDIO_CUR_STREAM,
|
|
||||||
CUSTOM_COMMAND_SUBS_CUR_STREAM,
|
|
||||||
CUSTOM_COMMAND_TRICK_SEEK,
|
|
||||||
CUSTOM_COMMAND_SET_SUB_SIZE,
|
|
||||||
CUSTOM_COMMAND_SET_SUB_ENCODING,
|
|
||||||
CUSTOM_COMMAND_SET_SUB_POS,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum event_msg {
|
|
||||||
EVENT_MSG_FDOPEN = 300,
|
|
||||||
EVENT_MSG_PLAYBACK_STARTED,
|
|
||||||
EVENT_MSG_STOPPED,
|
|
||||||
EVENT_MSG_PAUSED,
|
|
||||||
EVENT_MSG_BUFFERING,
|
|
||||||
EVENT_MSG_EOS,
|
|
||||||
EVENT_MSG_SUB_CHANGED,
|
|
||||||
};
|
|
||||||
|
|
||||||
//int fd_cmd, fd_in, fd_out, fd_event, msg;
|
|
@@ -1,54 +0,0 @@
|
|||||||
/*
|
|
||||||
* determine the capabilities of the hardware.
|
|
||||||
* part of libstb-hal
|
|
||||||
*
|
|
||||||
* (C) 2010-2012 Stefan Seyfried
|
|
||||||
*
|
|
||||||
* License: GPL v2 or later
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <hardware_caps.h>
|
|
||||||
|
|
||||||
static int initialized = 0;
|
|
||||||
static hw_caps_t caps;
|
|
||||||
|
|
||||||
hw_caps_t *get_hwcaps(void)
|
|
||||||
{
|
|
||||||
if (initialized)
|
|
||||||
return ∩︀
|
|
||||||
|
|
||||||
memset(&caps, 0, sizeof(hw_caps_t));
|
|
||||||
|
|
||||||
initialized = 1;
|
|
||||||
caps.can_cpufreq = 0;
|
|
||||||
caps.can_shutdown = 1;
|
|
||||||
caps.display_type = HW_DISPLAY_LINE_TEXT;
|
|
||||||
caps.has_HDMI = 1;
|
|
||||||
caps.display_xres = 8;
|
|
||||||
caps.display_can_deepstandby = 0;
|
|
||||||
caps.display_has_statusline = 0;
|
|
||||||
caps.display_has_colon = 0;
|
|
||||||
strcpy(caps.boxvendor, "AZBox");
|
|
||||||
const char *tmp;
|
|
||||||
char buf[64];
|
|
||||||
int len = -1;
|
|
||||||
int fd = open("/proc/stb/info/model", O_RDONLY);
|
|
||||||
if (fd != -1) {
|
|
||||||
len = read(fd, buf, sizeof(buf) - 1);
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
if (len > 0) {
|
|
||||||
buf[len] = 0;
|
|
||||||
strcpy(caps.boxname, buf);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
strcpy(caps.boxname, "(unknown model)");
|
|
||||||
|
|
||||||
return ∩︀
|
|
||||||
}
|
|
@@ -1,23 +0,0 @@
|
|||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "init.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;
|
|
||||||
|
|
||||||
void hal_api_init()
|
|
||||||
{
|
|
||||||
if (!initialized)
|
|
||||||
hal_debug_init();
|
|
||||||
hal_info("%s begin, initialized=%d, debug=0x%02x\n", __func__, (int)initialized, debuglevel);
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void hal_api_exit()
|
|
||||||
{
|
|
||||||
hal_info("%s, initialized = %d\n", __func__, (int)initialized);
|
|
||||||
initialized = false;
|
|
||||||
}
|
|
@@ -1,521 +0,0 @@
|
|||||||
/*
|
|
||||||
* cPlayback implementation for azbox
|
|
||||||
* this is actually just a wrapper around rmfp_player which does
|
|
||||||
* all the heavy listing
|
|
||||||
*
|
|
||||||
* based on the original aztrino implementation, but almost
|
|
||||||
* completely rewritten since then
|
|
||||||
*
|
|
||||||
* some of the methods and constants were found by stracing the
|
|
||||||
* AZPlay enigma2 plugin...
|
|
||||||
*
|
|
||||||
* (C) 2012 Stefan Seyfried
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sstream>
|
|
||||||
#include <pty.h>
|
|
||||||
#include <sys/poll.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/wait.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 <proc_tools.h>
|
|
||||||
|
|
||||||
/* the file-based commands work better than the FIFOs... */
|
|
||||||
#define CMD_FILE "/tmp/rmfp.cmd2"
|
|
||||||
#define IN_FILE "/tmp/rmfp.in2"
|
|
||||||
#define OUT_FILE "/tmp/rmfp.out2"
|
|
||||||
|
|
||||||
#include "playback_lib.h"
|
|
||||||
|
|
||||||
extern "C"{
|
|
||||||
#include "e2mruainclude.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* useful for debugging */
|
|
||||||
static time_t monotonic_ms(void)
|
|
||||||
{
|
|
||||||
struct timespec t;
|
|
||||||
time_t ret;
|
|
||||||
if (clock_gettime(CLOCK_MONOTONIC, &t))
|
|
||||||
{
|
|
||||||
perror("monotonic_ms clock_gettime");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
ret = ((t.tv_sec + 604800)& 0x01FFFFF) * 1000; /* avoid overflow */
|
|
||||||
ret += t.tv_nsec / 1000000;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* the mutex makes sure that commands are not interspersed */
|
|
||||||
bool cPlayback::rmfp_command(int cmd, int param, bool has_param, char *buf, int buflen)
|
|
||||||
{
|
|
||||||
hal_info("%s: %d %d %d %d\n", __func__, cmd, param, has_param, buflen);
|
|
||||||
bool ret = true;
|
|
||||||
int fd;
|
|
||||||
if (cmd == 222)
|
|
||||||
{
|
|
||||||
if (pthread_mutex_trylock(&rmfp_cmd_mutex))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
pthread_mutex_lock(&rmfp_cmd_mutex);
|
|
||||||
unlink(OUT_FILE);
|
|
||||||
if (has_param)
|
|
||||||
{
|
|
||||||
fd = open(IN_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0666);
|
|
||||||
dprintf(fd, "%i", param);
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
fd = open(CMD_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0666);
|
|
||||||
dprintf(fd, "%i", cmd);
|
|
||||||
close(fd);
|
|
||||||
int n = 0, m = 0;
|
|
||||||
if (buflen > 0)
|
|
||||||
{
|
|
||||||
while ((fd = open(OUT_FILE, O_RDONLY)) == -1) {
|
|
||||||
if (++m > 500) { /* don't wait more than 5 seconds */
|
|
||||||
hal_info("%s: timed out waiting for %s (cmd %d par %d buflen %d\n",
|
|
||||||
__func__, OUT_FILE, cmd, param, buflen);
|
|
||||||
ret = false;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
usleep(10000);
|
|
||||||
}
|
|
||||||
unlink(OUT_FILE);
|
|
||||||
n = read(fd, buf, buflen);
|
|
||||||
close(fd);
|
|
||||||
/* some commands (CUSTOM_COMMAND_GET_AUDIO_BY_ID for example) actually
|
|
||||||
* return the answer in two successive writes, as we are not using the
|
|
||||||
* FIFO, we need to make sure that the file is deleted immediately, because
|
|
||||||
* rmfp_player will not overwrite it if it exists */
|
|
||||||
while ((fd = open(OUT_FILE, O_RDONLY)) == -1) {
|
|
||||||
if (++m > 10)
|
|
||||||
break;
|
|
||||||
usleep(1000);
|
|
||||||
}
|
|
||||||
if (fd > -1)
|
|
||||||
{
|
|
||||||
read(fd, buf + n, buflen - n);
|
|
||||||
unlink(OUT_FILE);
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
buf[buflen - 1] = '0';
|
|
||||||
}
|
|
||||||
out:
|
|
||||||
pthread_mutex_unlock(&rmfp_cmd_mutex);
|
|
||||||
if (cmd != 222) /* called tooo often :-) */
|
|
||||||
hal_info("%s: reply: '%s' ret: %d m:%d\n", __func__, buf?buf:"(none)", ret, m);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* runs the rmfp_player in a terminal
|
|
||||||
* just doing popen() or similar does not work because then
|
|
||||||
* the output will be buffered after starting up and we will only
|
|
||||||
* see "Playback has started..." after the player exits
|
|
||||||
*/
|
|
||||||
void cPlayback::run_rmfp()
|
|
||||||
{
|
|
||||||
hal_debug("%s: starting\n", __func__);
|
|
||||||
thread_started = true;
|
|
||||||
//Watch for the space at the end
|
|
||||||
std::string base = "rmfp_player -dram 1 -ve 1 -waitexit ";
|
|
||||||
std::string filename(mfilename);
|
|
||||||
std::string file = '"' + filename + '"';
|
|
||||||
std::string final = base + file;
|
|
||||||
|
|
||||||
if (playMode == PLAYMODE_TS && mduration != 0)
|
|
||||||
{
|
|
||||||
std::stringstream duration;
|
|
||||||
duration << (mduration /** 60000LL*/);
|
|
||||||
final = base + "-duration " + duration.str() + " " + file;
|
|
||||||
}
|
|
||||||
|
|
||||||
pid_t pid = 0;
|
|
||||||
int master;
|
|
||||||
pid = forkpty(&master, NULL, NULL, NULL);
|
|
||||||
if (! pid) {
|
|
||||||
execl("/bin/sh", "sh", "-c", final.c_str(), (char *)0);
|
|
||||||
hal_info("%s: execl returned: %m\n", __func__);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pid > 0) {
|
|
||||||
char *output=NULL;
|
|
||||||
size_t n = 0;
|
|
||||||
ssize_t len;
|
|
||||||
FILE *f = fdopen(master, "r");
|
|
||||||
while ((len = getline(&output, &n, f)) != -1)
|
|
||||||
{
|
|
||||||
while (len > 0)
|
|
||||||
{
|
|
||||||
len--;
|
|
||||||
if (!isspace(output[len]))
|
|
||||||
break;
|
|
||||||
output[len] = '\0';
|
|
||||||
}
|
|
||||||
hal_info("%s out: '%s'\n", __func__, output);
|
|
||||||
if (strstr(output, "Playback has started..."))
|
|
||||||
{
|
|
||||||
playing = 1;
|
|
||||||
hal_info("%s: ===================> playing = true\n", __func__);
|
|
||||||
}
|
|
||||||
else if (strstr(output, "End of file..."))
|
|
||||||
{
|
|
||||||
playing = 1; /* this can happen without "Playback has started..." */
|
|
||||||
eof_reached = true;
|
|
||||||
hal_info("%s: ===================> eof_reached = true\n", __func__);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fclose(f);
|
|
||||||
int s;
|
|
||||||
while (waitpid(pid, &s, WNOHANG) > 0) {};
|
|
||||||
if (output)
|
|
||||||
free(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
hal_info("%s: terminating\n", __func__);
|
|
||||||
if (playing == 0) /* playback did not start */
|
|
||||||
playing = 2;
|
|
||||||
else
|
|
||||||
playing = 0;
|
|
||||||
eof_reached = true;
|
|
||||||
pthread_exit(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* helper function to call the cpp thread loop */
|
|
||||||
void *execute_rua_thread(void *c)
|
|
||||||
{
|
|
||||||
cPlayback *obj = (cPlayback *)c;
|
|
||||||
hal_info_c("%s\n", __func__);
|
|
||||||
obj->run_rmfp();
|
|
||||||
/* free(obj); // this is most likely wrong */
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Used by Fileplay
|
|
||||||
bool cPlayback::Open(playmode_t PlayMode)
|
|
||||||
{
|
|
||||||
static const char *aPLAYMODE[] = {
|
|
||||||
"PLAYMODE_TS",
|
|
||||||
"PLAYMODE_FILE"
|
|
||||||
};
|
|
||||||
playMode = PlayMode;
|
|
||||||
if (playMode > 1)
|
|
||||||
{
|
|
||||||
hal_info("%s: PlayMode %d out of range!\n", __func__, PlayMode);
|
|
||||||
playMode = PLAYMODE_FILE;
|
|
||||||
}
|
|
||||||
|
|
||||||
hal_info("%s: mode %d (%s)\n", __func__, PlayMode, aPLAYMODE[PlayMode]);
|
|
||||||
#if 0
|
|
||||||
while (access("/tmp/continue", R_OK))
|
|
||||||
sleep(1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
char c[2] = "0";
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
proc_get("/proc/player", c, 2);
|
|
||||||
if (c[0] != '0')
|
|
||||||
break;
|
|
||||||
i++;
|
|
||||||
if (i > 10)
|
|
||||||
{
|
|
||||||
hal_info("%s: ERROR - player is not idle after 10 seconds!\n", __func__);
|
|
||||||
open_success = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
sleep(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
proc_put("/proc/player", "2", 2);
|
|
||||||
hal_info("%s: /proc/player switched to '2'\n", __func__);
|
|
||||||
|
|
||||||
unlink(CMD_FILE);
|
|
||||||
unlink(IN_FILE);
|
|
||||||
unlink(OUT_FILE);
|
|
||||||
|
|
||||||
open_success = true;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Used by Fileplay
|
|
||||||
bool cPlayback::Start(char *filename, unsigned short vpid, int vtype, unsigned short _apid,
|
|
||||||
int ac3, unsigned int duration)
|
|
||||||
{
|
|
||||||
bool ret = true;
|
|
||||||
|
|
||||||
hal_info("%s: filename=%s\n", __func__, filename);
|
|
||||||
hal_info("%s: vpid=%u vtype=%d apid=%u ac3=%d duration=%i open_success=%d\n",
|
|
||||||
__func__, vpid, vtype, _apid, ac3, duration, open_success);
|
|
||||||
|
|
||||||
if (!open_success)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
eof_reached = false;
|
|
||||||
//create playback path
|
|
||||||
apid = 0;
|
|
||||||
subpid = 0;
|
|
||||||
mfilename = filename;
|
|
||||||
mduration = duration;
|
|
||||||
if (pthread_create(&thread, 0, execute_rua_thread, this) != 0)
|
|
||||||
{
|
|
||||||
hal_info("%s: error creating rmfp_player thread! (out of memory?)\n", __func__);
|
|
||||||
ret = false;
|
|
||||||
}
|
|
||||||
while (! playing)
|
|
||||||
sleep(1);
|
|
||||||
if (playing == 2)
|
|
||||||
playing = 0;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cPlayback::Close(void)
|
|
||||||
{
|
|
||||||
hal_info("%s: playing %d thread_started %d\n", __func__, playing, thread_started);
|
|
||||||
|
|
||||||
if (thread_started)
|
|
||||||
{
|
|
||||||
rmfp_command(KEY_COMMAND_QUIT_ALL, 0, false, NULL, 0);
|
|
||||||
|
|
||||||
if (pthread_join(thread, NULL))
|
|
||||||
hal_info("%s: error joining rmfp thread (%m)\n", __func__);
|
|
||||||
playing = 0;
|
|
||||||
thread_started = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
hal_info("%s: Warning: thread_started == false!\n", __func__);
|
|
||||||
|
|
||||||
if (open_success)
|
|
||||||
{
|
|
||||||
proc_put("/proc/player", "1", 2);
|
|
||||||
open_success = false;
|
|
||||||
hal_info("%s: /proc/player switched to '1'\n", __func__);
|
|
||||||
usleep(1000000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cPlayback::SetAPid(unsigned short pid, int /*ac3*/)
|
|
||||||
{
|
|
||||||
hal_info("%s: pid %i\n", __func__, pid);
|
|
||||||
if (pid != apid) {
|
|
||||||
rmfp_command(KEY_COMMAND_SWITCH_AUDIO, pid, true, NULL, 0);
|
|
||||||
apid = pid;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cPlayback::SelectSubtitles(int pid)
|
|
||||||
{
|
|
||||||
hal_info("%s: pid %i\n", __func__, pid);
|
|
||||||
if (pid != subpid)
|
|
||||||
{
|
|
||||||
rmfp_command(KEY_COMMAND_SWITCH_SUBS, pid, true, NULL, 0);
|
|
||||||
subpid = pid;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cPlayback::SetSpeed(int speed)
|
|
||||||
{
|
|
||||||
hal_info("%s: playing %d speed %d\n", __func__, playing, speed);
|
|
||||||
|
|
||||||
if (!playing)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
playback_speed = speed;
|
|
||||||
|
|
||||||
if (speed > 1 || speed < 0)
|
|
||||||
rmfp_command(CUSTOM_COMMAND_TRICK_SEEK, speed, true, NULL, 0);
|
|
||||||
else if (speed == 0)
|
|
||||||
rmfp_command(KEY_COMMAND_PAUSE, 0, false, NULL, 0);
|
|
||||||
else
|
|
||||||
rmfp_command(KEY_COMMAND_PLAY, 0, false, NULL, 0);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cPlayback::GetSpeed(int &/*speed*/) const
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
hal_info("%s:\n", __func__);
|
|
||||||
speed = playback_speed;
|
|
||||||
#endif
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// in milliseconds
|
|
||||||
bool cPlayback::GetPosition(int &position, int &duration)
|
|
||||||
{
|
|
||||||
hal_debug("%s: playing %d\n", __func__, playing);
|
|
||||||
|
|
||||||
if (eof_reached)
|
|
||||||
{
|
|
||||||
position = mduration;
|
|
||||||
duration = mduration;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!playing)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
char buf[32];
|
|
||||||
/* custom command 222 returns "12345\n1234\n",
|
|
||||||
* first line is duration, second line is position */
|
|
||||||
if (! rmfp_command(222, 0, false, buf, 32))
|
|
||||||
return false;
|
|
||||||
duration = atoi(buf);
|
|
||||||
char *p = strchr(buf, '\n');
|
|
||||||
if (!p)
|
|
||||||
return false;
|
|
||||||
position = atoi(++p);
|
|
||||||
/* some mpegs return length 0... which would lead to "eof" after 10 seconds */
|
|
||||||
if (duration == 0)
|
|
||||||
duration = position + 1000;
|
|
||||||
|
|
||||||
if (playMode == PLAYMODE_TS)
|
|
||||||
{
|
|
||||||
if (position > mduration)
|
|
||||||
mduration = position + 1000;
|
|
||||||
duration = mduration;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cPlayback::SetPosition(int position, bool absolute)
|
|
||||||
{
|
|
||||||
hal_info("%s: pos %d abs %d playing %d\n", __func__, position, absolute, playing);
|
|
||||||
|
|
||||||
if (!playing)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
int seconds = position / 1000;;
|
|
||||||
|
|
||||||
if (absolute)
|
|
||||||
{
|
|
||||||
rmfp_command(KEY_COMMAND_SEEK_TO_TIME, seconds, true, NULL, 0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (position > 0)
|
|
||||||
rmfp_command(CUSTOM_COMMAND_SEEK_RELATIVE_FWD, seconds, true, NULL, 0);
|
|
||||||
else if (position < 0)
|
|
||||||
rmfp_command(CUSTOM_COMMAND_SEEK_RELATIVE_BWD, seconds, true, NULL, 0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cPlayback::FindAllPids(uint16_t *apids, unsigned short *ac3flags, uint16_t *numpida, std::string *language)
|
|
||||||
{
|
|
||||||
hal_info("%s\n", __func__);
|
|
||||||
char buf[32];
|
|
||||||
rmfp_command(CUSTOM_COMMAND_AUDIO_COUNT, 0, false, buf, 3);
|
|
||||||
unsigned int audio_count = atoi(buf);
|
|
||||||
|
|
||||||
*numpida = audio_count;
|
|
||||||
if (audio_count > 0)
|
|
||||||
{
|
|
||||||
for (unsigned int aid = 0; aid < audio_count; aid++)
|
|
||||||
{
|
|
||||||
char streamidstring[11];
|
|
||||||
char audio_lang[21];
|
|
||||||
memset(buf, 0, sizeof(buf));
|
|
||||||
rmfp_command(CUSTOM_COMMAND_GET_AUDIO_BY_ID, aid, true, buf, 32);
|
|
||||||
memcpy(streamidstring, buf, 10);
|
|
||||||
streamidstring[10] = '\0';
|
|
||||||
memcpy(audio_lang, buf + 10, 20);
|
|
||||||
audio_lang[20] = '\0';
|
|
||||||
apids[aid] = atoi(streamidstring);
|
|
||||||
ac3flags[aid] = 0;
|
|
||||||
language[aid] = audio_lang;
|
|
||||||
hal_info("%s: #%d apid:%d lang: %s\n", __func__, aid, apids[aid], audio_lang);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void cPlayback::FindAllSubs(uint16_t *spids, unsigned short *supported, uint16_t *numpids, std::string *language)
|
|
||||||
{
|
|
||||||
hal_info("%s\n", __func__);
|
|
||||||
char buf[32];
|
|
||||||
|
|
||||||
rmfp_command(CUSTOM_COMMAND_SUBS_COUNT, 0, false, buf, 3);
|
|
||||||
unsigned int spu_count = atoi(buf);
|
|
||||||
*numpids = spu_count;
|
|
||||||
|
|
||||||
if (spu_count > 0)
|
|
||||||
{
|
|
||||||
for (unsigned int sid = 0; sid < spu_count; sid++)
|
|
||||||
{
|
|
||||||
char streamidstring[11];
|
|
||||||
char spu_lang[21];
|
|
||||||
memset(buf, 0, sizeof(buf));
|
|
||||||
rmfp_command(CUSTOM_COMMAND_GET_SUB_BY_ID, sid, true, buf, 32);
|
|
||||||
memcpy(streamidstring, buf, 10);
|
|
||||||
streamidstring[10] = '\0';
|
|
||||||
memcpy(spu_lang, buf + 10, 20);
|
|
||||||
spu_lang[20] = '\0';
|
|
||||||
spids[sid] = atoi(streamidstring);
|
|
||||||
language[sid] = spu_lang;
|
|
||||||
supported[sid] = 1;
|
|
||||||
hal_info("%s: #%d apid:%d lang: %s\n", __func__, sid, spids[sid], spu_lang);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Add streamid -1 to be able to disable subtitles
|
|
||||||
*numpids = spu_count + 1;
|
|
||||||
spids[spu_count] = -1;
|
|
||||||
language[spu_count] = "Disable";
|
|
||||||
}
|
|
||||||
|
|
||||||
/* DVD support is not yet ready... */
|
|
||||||
void cPlayback::GetChapters(std::vector<int> &positions, std::vector<std::string> &titles)
|
|
||||||
{
|
|
||||||
positions.clear();
|
|
||||||
titles.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
cPlayback::cPlayback(int /*num*/)
|
|
||||||
{
|
|
||||||
hal_info("%s: constructor\n", __func__);
|
|
||||||
playing = 0;
|
|
||||||
thread_started = false;
|
|
||||||
eof_reached = false;
|
|
||||||
open_success = false;
|
|
||||||
pthread_mutex_init(&rmfp_cmd_mutex, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
cPlayback::~cPlayback()
|
|
||||||
{
|
|
||||||
hal_info("%s\n", __func__);
|
|
||||||
pthread_mutex_destroy(&rmfp_cmd_mutex);
|
|
||||||
}
|
|
@@ -1,62 +0,0 @@
|
|||||||
#ifndef __PLAYBACK_LIB_H__
|
|
||||||
#define __PLAYBACK_LIB_H__
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
PLAYMODE_TS = 0,
|
|
||||||
PLAYMODE_FILE,
|
|
||||||
} playmode_t;
|
|
||||||
|
|
||||||
class cPlayback
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
pthread_mutex_t rmfp_cmd_mutex;
|
|
||||||
int playing;
|
|
||||||
bool eof_reached;
|
|
||||||
int playback_speed;
|
|
||||||
playmode_t playMode;
|
|
||||||
bool open_success;
|
|
||||||
uint16_t apid;
|
|
||||||
uint16_t subpid;
|
|
||||||
char *mfilename;
|
|
||||||
int mduration;
|
|
||||||
pthread_t thread;
|
|
||||||
bool thread_started;
|
|
||||||
/* private functions */
|
|
||||||
bool rmfp_command(int cmd, int param, bool has_param, char *buf, int buflen);
|
|
||||||
public:
|
|
||||||
cPlayback(int num = 0);
|
|
||||||
~cPlayback();
|
|
||||||
|
|
||||||
void run_rmfp();
|
|
||||||
|
|
||||||
bool Open(playmode_t PlayMode);
|
|
||||||
void Close(void);
|
|
||||||
bool Start(char *filename, unsigned short vpid, int vtype, unsigned short apid,
|
|
||||||
int ac3, unsigned int duration);
|
|
||||||
bool SetAPid(unsigned short pid, int ac3);
|
|
||||||
bool SetSpeed(int speed);
|
|
||||||
bool GetSpeed(int &speed) const;
|
|
||||||
bool GetPosition(int &position, int &duration); /* pos: current time in ms, dur: file length in ms */
|
|
||||||
bool SetPosition(int position, bool absolute = false); /* position: jump in ms */
|
|
||||||
void FindAllPids(uint16_t *apids, unsigned short *ac3flags, uint16_t *numpida, std::string *language);
|
|
||||||
void FindAllSubs(uint16_t *pids, unsigned short *supported, uint16_t *numpida, std::string *language);
|
|
||||||
bool SelectSubtitles(int pid);
|
|
||||||
void GetChapters(std::vector<int> &positions, std::vector<std::string> &titles);
|
|
||||||
#if 0
|
|
||||||
// Functions that are not used by movieplayer.cpp:
|
|
||||||
bool Stop(void);
|
|
||||||
bool GetOffset(off64_t &offset);
|
|
||||||
bool IsPlaying(void) const { return playing; }
|
|
||||||
bool IsEnabled(void) const { return enabled; }
|
|
||||||
void * GetHandle(void);
|
|
||||||
void * GetDmHandle(void);
|
|
||||||
int GetCurrPlaybackSpeed(void) const { return nPlaybackSpeed; }
|
|
||||||
void PlaybackNotify (int Event, void *pData, void *pTag);
|
|
||||||
void DMNotify(int Event, void *pTsBuf, void *Tag);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
#endif // __PLAYBACK_LIB_H__
|
|
@@ -1 +0,0 @@
|
|||||||
../libspark/record.cpp
|
|
@@ -1 +0,0 @@
|
|||||||
../libspark/record_lib.h
|
|
@@ -1,639 +0,0 @@
|
|||||||
/*
|
|
||||||
* (C) 2002-2003 Andreas Oberritter <obi@tuxbox.org>
|
|
||||||
* (C) 2010-2012 Stefan Seyfried
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <utime.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
#include <linux/types.h>
|
|
||||||
#include <linux/dvb/video.h>
|
|
||||||
|
|
||||||
#include <proc_tools.h>
|
|
||||||
|
|
||||||
#include "video_lib.h"
|
|
||||||
#define VIDEO_DEVICE "/dev/dvb/adapter0/video0"
|
|
||||||
#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 hal_debug_c(args...) _hal_debug(HAL_DEBUG_VIDEO, NULL, args)
|
|
||||||
#define hal_info_c(args...) _hal_info(HAL_DEBUG_VIDEO, NULL, 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;
|
|
||||||
|
|
||||||
static bool stillpicture = false;
|
|
||||||
static unsigned char *blank_data;
|
|
||||||
static ssize_t blank_size;
|
|
||||||
static pthread_mutex_t stillp_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
||||||
/* prototype */
|
|
||||||
static void show_iframe(int fd, unsigned char *iframe, size_t st_size);
|
|
||||||
|
|
||||||
#define VIDEO_STREAMTYPE_MPEG2 0
|
|
||||||
#define VIDEO_STREAMTYPE_MPEG4_H264 1
|
|
||||||
#define VIDEO_STREAMTYPE_VC1 3
|
|
||||||
#define VIDEO_STREAMTYPE_MPEG4_Part2 4
|
|
||||||
#define VIDEO_STREAMTYPE_VC1_SM 5
|
|
||||||
#define VIDEO_STREAMTYPE_MPEG1 6
|
|
||||||
|
|
||||||
cVideo::cVideo(int, void *, void *, unsigned int)
|
|
||||||
{
|
|
||||||
hal_debug("%s\n", __FUNCTION__);
|
|
||||||
|
|
||||||
//croppingMode = VID_DISPMODE_NORM;
|
|
||||||
//outputformat = VID_OUTFMT_RGBC_SVIDEO;
|
|
||||||
scartvoltage = -1;
|
|
||||||
video_standby = 0;
|
|
||||||
fd = -1;
|
|
||||||
|
|
||||||
const char *blankname = "/share/tuxbox/blank_576.mpg";
|
|
||||||
int blankfd;
|
|
||||||
struct stat st;
|
|
||||||
|
|
||||||
blank_data = NULL; /* initialize */
|
|
||||||
blank_size = 0;
|
|
||||||
blankfd = open(blankname, O_RDONLY|O_CLOEXEC);
|
|
||||||
if (blankfd < 0)
|
|
||||||
hal_info("%s cannot open %s: %m", __func__, blankname);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (fstat(blankfd, &st) != -1 && st.st_size > 0)
|
|
||||||
{
|
|
||||||
blank_size = st.st_size;
|
|
||||||
blank_data = (unsigned char *)malloc(blank_size);
|
|
||||||
if (! blank_data)
|
|
||||||
hal_info("%s malloc failed (%m)\n", __func__);
|
|
||||||
else if (read(blankfd, blank_data, blank_size) != blank_size)
|
|
||||||
{
|
|
||||||
hal_info("%s short read (%m)\n", __func__);
|
|
||||||
free(blank_data); /* don't leak... */
|
|
||||||
blank_data = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(blankfd);
|
|
||||||
}
|
|
||||||
openDevice();
|
|
||||||
Pig(-1, -1, -1, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
cVideo::~cVideo(void)
|
|
||||||
{
|
|
||||||
closeDevice();
|
|
||||||
if (blank_data)
|
|
||||||
free(blank_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cVideo::openDevice(void)
|
|
||||||
{
|
|
||||||
int n = 0;
|
|
||||||
hal_debug("%s\n", __func__);
|
|
||||||
/* todo: this fd checking is racy, should be protected by a lock */
|
|
||||||
if (fd != -1) /* already open */
|
|
||||||
return;
|
|
||||||
retry:
|
|
||||||
if ((fd = open(VIDEO_DEVICE, O_RDWR|O_CLOEXEC)) < 0)
|
|
||||||
{
|
|
||||||
if (errno == EBUSY)
|
|
||||||
{
|
|
||||||
/* sometimes we get busy quickly after close() */
|
|
||||||
usleep(50000);
|
|
||||||
if (++n < 10)
|
|
||||||
goto retry;
|
|
||||||
}
|
|
||||||
hal_info("%s cannot open %s: %m, retries %d\n", __func__, VIDEO_DEVICE, n);
|
|
||||||
}
|
|
||||||
playstate = VIDEO_STOPPED;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cVideo::closeDevice(void)
|
|
||||||
{
|
|
||||||
hal_debug("%s\n", __func__);
|
|
||||||
if (fd >= 0)
|
|
||||||
close(fd);
|
|
||||||
fd = -1;
|
|
||||||
playstate = VIDEO_STOPPED;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cVideo::setAspectRatio(int aspect, int mode)
|
|
||||||
{
|
|
||||||
static const char *a[] = { "n/a", "4:3", "14:9", "16:9" };
|
|
||||||
/* { "panscan", "letterbox", "fullscreen", "14:9", "(unset)" } */
|
|
||||||
static const char *m[] = { "1", "2", "0", "1", "(unset)" };
|
|
||||||
int n;
|
|
||||||
|
|
||||||
int mo = (mode < 0||mode > 3) ? 4 : mode;
|
|
||||||
hal_debug("%s: a:%d m:%d %s\n", __func__, aspect, mode, m[(mo)]);
|
|
||||||
|
|
||||||
if (aspect > 3 || aspect == 0)
|
|
||||||
hal_info("%s: invalid aspect: %d\n", __func__, aspect);
|
|
||||||
else if (aspect > 0) /* -1 == don't set */
|
|
||||||
{
|
|
||||||
hal_debug("%s: /proc/stb/video/aspect -> %s\n", __func__, a[aspect]);
|
|
||||||
n = proc_put("/proc/stb/video/aspect", a[aspect], strlen(a[aspect]));
|
|
||||||
if (n < 0)
|
|
||||||
hal_info("%s: proc_put /proc/stb/video/aspect (%m)\n", __func__);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode == -1)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
hal_debug("%s: /proc/scalingmode -> %s\n", __func__, m[mo]);
|
|
||||||
n = proc_put("/proc/scalingmode", m[mo], strlen(m[mo]));
|
|
||||||
if (n < 0)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cVideo::getAspectRatio(void)
|
|
||||||
{
|
|
||||||
video_size_t s;
|
|
||||||
if (fd == -1)
|
|
||||||
{
|
|
||||||
/* in movieplayer mode, fd is not opened -> fall back to procfs */
|
|
||||||
int n = proc_get_hex("/proc/stb/vmpeg/0/aspect");
|
|
||||||
return n * 2 + 1;
|
|
||||||
}
|
|
||||||
if (fop(ioctl, VIDEO_GET_SIZE, &s) < 0)
|
|
||||||
{
|
|
||||||
hal_info("%s: VIDEO_GET_SIZE %m\n", __func__);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
hal_debug("%s: %d\n", __func__, s.aspect_ratio);
|
|
||||||
return s.aspect_ratio * 2 + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cVideo::setCroppingMode(int /*vidDispMode_t format*/)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
#if 0
|
|
||||||
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);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int cVideo::Start(void * /*PcrChannel*/, unsigned short /*PcrPid*/, unsigned short /*VideoPid*/, void * /*hChannel*/)
|
|
||||||
{
|
|
||||||
hal_debug("%s playstate=%d\n", __FUNCTION__, playstate);
|
|
||||||
#if 0
|
|
||||||
if (playstate == VIDEO_PLAYING)
|
|
||||||
return 0;
|
|
||||||
if (playstate == VIDEO_FREEZED) /* in theory better, but not in practice :-) */
|
|
||||||
fop(ioctl, MPEG_VID_CONTINUE);
|
|
||||||
#endif
|
|
||||||
playstate = VIDEO_PLAYING;
|
|
||||||
return fop(ioctl, VIDEO_PLAY);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cVideo::Stop(bool blank)
|
|
||||||
{
|
|
||||||
hal_debug("%s(%d)\n", __FUNCTION__, blank);
|
|
||||||
if (stillpicture)
|
|
||||||
{
|
|
||||||
hal_debug("%s: stillpicture == true\n", __func__);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
/* blank parameter seems to not work on VIDEO_STOP */
|
|
||||||
if (blank)
|
|
||||||
setBlank(1);
|
|
||||||
playstate = blank ? VIDEO_STOPPED : VIDEO_FREEZED;
|
|
||||||
return fop(ioctl, VIDEO_STOP, blank ? 1 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cVideo::setBlank(int)
|
|
||||||
{
|
|
||||||
pthread_mutex_lock(&stillp_mutex);
|
|
||||||
if (blank_data)
|
|
||||||
show_iframe(fd, blank_data, blank_size);
|
|
||||||
pthread_mutex_unlock(&stillp_mutex);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cVideo::SetVideoSystem(int video_system, bool remember)
|
|
||||||
{
|
|
||||||
hal_debug("%s(%d, %d)\n", __func__, video_system, remember);
|
|
||||||
char current[32];
|
|
||||||
static const char *modes[] = {
|
|
||||||
"480i", // VIDEO_STD_NTSC
|
|
||||||
"576i", // VIDEO_STD_SECAM
|
|
||||||
"576i", // VIDEO_STD_PAL
|
|
||||||
"480p", // VIDEO_STD_480P
|
|
||||||
"576p", // VIDEO_STD_576P
|
|
||||||
"720p60", // VIDEO_STD_720P60
|
|
||||||
"1080i60", // VIDEO_STD_1080I60
|
|
||||||
"720p50", // VIDEO_STD_720P50
|
|
||||||
"1080i50", // VIDEO_STD_1080I50
|
|
||||||
"1080p30", // VIDEO_STD_1080P30
|
|
||||||
"1080p24", // VIDEO_STD_1080P24
|
|
||||||
"1080p25", // VIDEO_STD_1080P25
|
|
||||||
"720p50", // VIDEO_STD_AUTO -> not implemented
|
|
||||||
"1080p50" // VIDEO_STD_1080P50 -> SPARK only
|
|
||||||
};
|
|
||||||
|
|
||||||
if (video_system > VIDEO_STD_MAX)
|
|
||||||
{
|
|
||||||
hal_info("%s: video_system (%d) > VIDEO_STD_MAX (%d)\n", __func__, video_system, VIDEO_STD_MAX);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
int ret = proc_get("/proc/stb/video/videomode", current, 32);
|
|
||||||
if (strcmp(current, modes[video_system]) == 0)
|
|
||||||
{
|
|
||||||
hal_info("%s: video_system %d (%s) already set, skipping\n", __func__, video_system, current);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
hal_info("%s: old: '%s' new: '%s'\n", __func__, current, modes[video_system]);
|
|
||||||
ret = proc_put("/proc/stb/video/videomode", modes[video_system],strlen(modes[video_system]));
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cVideo::getPlayState(void)
|
|
||||||
{
|
|
||||||
return playstate;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cVideo::SetVideoMode(analog_mode_t mode)
|
|
||||||
{
|
|
||||||
hal_debug("%s(%d)\n", __func__, mode);
|
|
||||||
if (!(mode & ANALOG_SCART_MASK))
|
|
||||||
{
|
|
||||||
hal_debug("%s: non-SCART mode ignored\n", __func__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const char *m;
|
|
||||||
switch(mode)
|
|
||||||
{
|
|
||||||
case ANALOG_SD_YPRPB_SCART:
|
|
||||||
m = "yuv";
|
|
||||||
break;
|
|
||||||
case ANALOG_SD_RGB_SCART:
|
|
||||||
m = "rgb";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
hal_info("%s unknown mode %d\n", __func__, mode);
|
|
||||||
m = "rgb";
|
|
||||||
break; /* default to rgb */
|
|
||||||
}
|
|
||||||
proc_put("/proc/stb/avs/0/colorformat", m, strlen(m));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cVideo::ShowPicture(const char * fname)
|
|
||||||
{
|
|
||||||
bool ret = false;
|
|
||||||
hal_debug("%s(%s)\n", __func__, fname);
|
|
||||||
char destname[512];
|
|
||||||
char cmd[512];
|
|
||||||
char *p;
|
|
||||||
int mfd;
|
|
||||||
unsigned char *iframe;
|
|
||||||
struct stat st, st2;
|
|
||||||
if (video_standby)
|
|
||||||
{
|
|
||||||
/* does not work and the driver does not seem to like it */
|
|
||||||
hal_info("%s: video_standby == true\n", __func__);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
if (fd == -1)
|
|
||||||
{
|
|
||||||
hal_info("%s: decoder not opened\n", __func__);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
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 1280x720 '%s' </dev/null",
|
|
||||||
fname, destname);
|
|
||||||
system(cmd); /* TODO: use libavcodec to directly convert it */
|
|
||||||
utime(destname, &u);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* the mutex is a workaround: setBlank is apparently called from
|
|
||||||
a differnt thread and takes slightly longer, so that the decoder
|
|
||||||
was blanked immediately after displaying the image, which is not
|
|
||||||
what we want. the mutex ensures proper ordering. */
|
|
||||||
pthread_mutex_lock(&stillp_mutex);
|
|
||||||
|
|
||||||
mfd = open(destname, O_RDONLY|O_CLOEXEC);
|
|
||||||
if (mfd < 0)
|
|
||||||
{
|
|
||||||
hal_info("%s cannot open %s: %m", __func__, destname);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
fstat(mfd, &st);
|
|
||||||
|
|
||||||
stillpicture = true;
|
|
||||||
|
|
||||||
iframe = (unsigned char *)malloc(st.st_size);
|
|
||||||
if (! iframe)
|
|
||||||
{
|
|
||||||
hal_info("%s: malloc failed (%m)\n", __func__);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
read(mfd, iframe, st.st_size);
|
|
||||||
show_iframe(fd, iframe, st.st_size);
|
|
||||||
free(iframe);
|
|
||||||
ret = true;
|
|
||||||
out:
|
|
||||||
close(mfd);
|
|
||||||
pthread_mutex_unlock(&stillp_mutex);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cVideo::StopPicture()
|
|
||||||
{
|
|
||||||
hal_debug("%s\n", __func__);
|
|
||||||
stillpicture = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cVideo::Standby(unsigned int bOn)
|
|
||||||
{
|
|
||||||
hal_debug("%s(%d)\n", __func__, bOn);
|
|
||||||
if (bOn)
|
|
||||||
{
|
|
||||||
closeDevice();
|
|
||||||
proc_put("/proc/stb/avs/0/input", "aux", 4);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
proc_put("/proc/stb/avs/0/input", "encoder", 8);
|
|
||||||
openDevice();
|
|
||||||
}
|
|
||||||
video_standby = bOn;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cVideo::getBlank(void)
|
|
||||||
{
|
|
||||||
int ret = proc_get_hex("/proc/stb/vmpeg/0/xres");
|
|
||||||
hal_debug("%s => %d\n", __func__, !ret);
|
|
||||||
return !ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* this function is regularly called, checks if video parameters
|
|
||||||
changed and triggers appropriate actions */
|
|
||||||
void cVideo::VideoParamWatchdog(void)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
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;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void cVideo::Pig(int x, int y, int w, int h, int osd_w, int osd_h)
|
|
||||||
{
|
|
||||||
char buffer[64];
|
|
||||||
int _x, _y, _w, _h;
|
|
||||||
/* the target "coordinates" seem to be in a PAL sized plane
|
|
||||||
* TODO: check this in the driver sources */
|
|
||||||
int xres = 720; /* proc_get_hex("/proc/stb/vmpeg/0/xres") */
|
|
||||||
int yres = 576; /* proc_get_hex("/proc/stb/vmpeg/0/yres") */
|
|
||||||
hal_debug("%s: x:%d y:%d w:%d h:%d ow:%d oh:%d\n", __func__, x, y, w, h, osd_w, osd_h);
|
|
||||||
if (x == -1 && y == -1 && w == -1 && h == -1)
|
|
||||||
{
|
|
||||||
_w = xres;
|
|
||||||
_h = yres;
|
|
||||||
_x = 0;
|
|
||||||
_y = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_x = x * xres / osd_w;
|
|
||||||
_w = w * xres / osd_w;
|
|
||||||
_y = y * yres / osd_h;
|
|
||||||
_h = h * yres / osd_h;
|
|
||||||
}
|
|
||||||
hal_debug("%s: x:%d y:%d w:%d h:%d xr:%d yr:%d\n", __func__, _x, _y, _w, _h, xres, yres);
|
|
||||||
sprintf(buffer, "%x", _x);
|
|
||||||
proc_put("/proc/stb/vmpeg/0/dst_left", buffer, strlen(buffer));
|
|
||||||
sprintf(buffer, "%x", _y);
|
|
||||||
proc_put("/proc/stb/vmpeg/0/dst_top", buffer, strlen(buffer));
|
|
||||||
sprintf(buffer, "%x", _w);
|
|
||||||
proc_put("/proc/stb/vmpeg/0/dst_width", buffer, strlen(buffer));
|
|
||||||
sprintf(buffer, "%x", _h);
|
|
||||||
proc_put("/proc/stb/vmpeg/0/dst_height", buffer, strlen(buffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int rate2csapi(int rate)
|
|
||||||
{
|
|
||||||
switch (rate)
|
|
||||||
{
|
|
||||||
/* no idea how the float values are represented by the driver */
|
|
||||||
case 23976:
|
|
||||||
return 0;
|
|
||||||
case 24:
|
|
||||||
return 1;
|
|
||||||
case 25:
|
|
||||||
return 2;
|
|
||||||
case 29970:
|
|
||||||
return 3;
|
|
||||||
case 30:
|
|
||||||
return 4;
|
|
||||||
case 50:
|
|
||||||
return 5;
|
|
||||||
case 59940:
|
|
||||||
return 6;
|
|
||||||
case 60:
|
|
||||||
return 7;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cVideo::getPictureInfo(int &width, int &height, int &rate)
|
|
||||||
{
|
|
||||||
video_size_t s;
|
|
||||||
int r;
|
|
||||||
if (fd == -1)
|
|
||||||
{
|
|
||||||
/* in movieplayer mode, fd is not opened -> fall back to procfs */
|
|
||||||
r = proc_get_hex("/proc/stb/vmpeg/0/framerate");
|
|
||||||
width = proc_get_hex("/proc/stb/vmpeg/0/xres");
|
|
||||||
height = proc_get_hex("/proc/stb/vmpeg/0/yres");
|
|
||||||
rate = rate2csapi(r);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ioctl(fd, VIDEO_GET_SIZE, &s);
|
|
||||||
ioctl(fd, VIDEO_GET_FRAME_RATE, &r);
|
|
||||||
rate = rate2csapi(r);
|
|
||||||
height = s.h;
|
|
||||||
width = s.w;
|
|
||||||
hal_debug("%s: rate: %d, width: %d height: %d\n", __func__, rate, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cVideo::SetSyncMode(AVSYNC_TYPE mode)
|
|
||||||
{
|
|
||||||
hal_debug("%s %d\n", __func__, mode);
|
|
||||||
/*
|
|
||||||
* { 0, LOCALE_OPTIONS_OFF },
|
|
||||||
* { 1, LOCALE_OPTIONS_ON },
|
|
||||||
* { 2, LOCALE_AUDIOMENU_AVSYNC_AM }
|
|
||||||
*/
|
|
||||||
#if 0
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
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"
|
|
||||||
};
|
|
||||||
int t;
|
|
||||||
hal_debug("%s type=%s\n", __FUNCTION__, VF[type]);
|
|
||||||
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case VIDEO_FORMAT_MPEG4:
|
|
||||||
t = VIDEO_STREAMTYPE_MPEG4_H264;
|
|
||||||
break;
|
|
||||||
case VIDEO_FORMAT_VC1:
|
|
||||||
t = VIDEO_STREAMTYPE_VC1;
|
|
||||||
break;
|
|
||||||
case VIDEO_FORMAT_MPEG2:
|
|
||||||
default:
|
|
||||||
t = VIDEO_STREAMTYPE_MPEG2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ioctl(fd, VIDEO_SET_STREAMTYPE, t) < 0)
|
|
||||||
hal_info("%s VIDEO_SET_STREAMTYPE(%d) failed: %m\n", __func__, t);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t cVideo::GetPTS(void)
|
|
||||||
{
|
|
||||||
int64_t pts = 0;
|
|
||||||
if (ioctl(fd, VIDEO_GET_PTS, &pts) < 0)
|
|
||||||
hal_info("%s: GET_PTS failed (%m)\n", __func__);
|
|
||||||
return pts;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void show_iframe(int fd, unsigned char *iframe, size_t st_size)
|
|
||||||
{
|
|
||||||
static const unsigned char pes_header[] = { 0, 0, 1, 0xE0, 0, 0, 0x80, 0x80, 5, 0x21, 0, 1, 0, 1};
|
|
||||||
static const unsigned char seq_end[] = { 0x00, 0x00, 0x01, 0xB7 };
|
|
||||||
unsigned char stuffing[128];
|
|
||||||
bool seq_end_avail = false;
|
|
||||||
size_t pos = 0;
|
|
||||||
int count = 7;
|
|
||||||
if (ioctl(fd, VIDEO_SET_FORMAT, VIDEO_FORMAT_16_9) < 0)
|
|
||||||
hal_info_c("%s: VIDEO_SET_FORMAT failed (%m)\n", __func__);
|
|
||||||
ioctl(fd, VIDEO_SET_STREAMTYPE, VIDEO_FORMAT_MPEG2);
|
|
||||||
ioctl(fd, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY);
|
|
||||||
ioctl(fd, VIDEO_PLAY);
|
|
||||||
ioctl(fd, VIDEO_CONTINUE);
|
|
||||||
ioctl(fd, VIDEO_CLEAR_BUFFER);
|
|
||||||
while (pos <= (st_size-4) && !(seq_end_avail = (!iframe[pos] && !iframe[pos+1] && iframe[pos+2] == 1 && iframe[pos+3] == 0xB7)))
|
|
||||||
++pos;
|
|
||||||
while (count--)
|
|
||||||
{
|
|
||||||
if ((iframe[3] >> 4) != 0xE) // no pes header
|
|
||||||
write(fd, pes_header, sizeof(pes_header));
|
|
||||||
else
|
|
||||||
iframe[4] = iframe[5] = 0x00;
|
|
||||||
write(fd, iframe, st_size);
|
|
||||||
usleep(8000);
|
|
||||||
}
|
|
||||||
if (!seq_end_avail)
|
|
||||||
write(fd, seq_end, sizeof(seq_end));
|
|
||||||
|
|
||||||
memset(stuffing, 0, sizeof(stuffing));
|
|
||||||
for (count = 0; count < 8192 / (int)sizeof(stuffing); count++)
|
|
||||||
write(fd, stuffing, sizeof(stuffing));
|
|
||||||
ioctl(fd, VIDEO_STOP, 0);
|
|
||||||
ioctl(fd, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cVideo::SetDemux(cDemux *)
|
|
||||||
{
|
|
||||||
hal_debug("%s: not implemented yet\n", __func__);
|
|
||||||
}
|
|
@@ -1,196 +0,0 @@
|
|||||||
#ifndef __VIDEO_LIB_H__
|
|
||||||
#define __VIDEO_LIB_H__
|
|
||||||
|
|
||||||
#include <linux/dvb/video.h>
|
|
||||||
#include "cs_types.h"
|
|
||||||
#include "dmx_hal.h"
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
ANALOG_SD_RGB_CINCH = 0x00,
|
|
||||||
ANALOG_SD_YPRPB_CINCH,
|
|
||||||
ANALOG_HD_RGB_CINCH,
|
|
||||||
ANALOG_HD_YPRPB_CINCH,
|
|
||||||
ANALOG_SD_RGB_SCART = 0x10,
|
|
||||||
ANALOG_SD_YPRPB_SCART,
|
|
||||||
ANALOG_HD_RGB_SCART,
|
|
||||||
ANALOG_HD_YPRPB_SCART,
|
|
||||||
ANALOG_SCART_MASK = 0x10
|
|
||||||
} analog_mode_t;
|
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
VIDEO_FORMAT_MPEG2 = 0,
|
|
||||||
VIDEO_FORMAT_MPEG4,
|
|
||||||
VIDEO_FORMAT_VC1,
|
|
||||||
VIDEO_FORMAT_JPEG,
|
|
||||||
VIDEO_FORMAT_GIF,
|
|
||||||
VIDEO_FORMAT_PNG
|
|
||||||
} VIDEO_FORMAT;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
VIDEO_SD = 0,
|
|
||||||
VIDEO_HD,
|
|
||||||
VIDEO_120x60i,
|
|
||||||
VIDEO_320x240i,
|
|
||||||
VIDEO_1440x800i,
|
|
||||||
VIDEO_360x288i
|
|
||||||
} VIDEO_DEFINITION;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
VIDEO_FRAME_RATE_23_976 = 0,
|
|
||||||
VIDEO_FRAME_RATE_24,
|
|
||||||
VIDEO_FRAME_RATE_25,
|
|
||||||
VIDEO_FRAME_RATE_29_97,
|
|
||||||
VIDEO_FRAME_RATE_30,
|
|
||||||
VIDEO_FRAME_RATE_50,
|
|
||||||
VIDEO_FRAME_RATE_59_94,
|
|
||||||
VIDEO_FRAME_RATE_60
|
|
||||||
} VIDEO_FRAME_RATE;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
DISPLAY_AR_1_1,
|
|
||||||
DISPLAY_AR_4_3,
|
|
||||||
DISPLAY_AR_14_9,
|
|
||||||
DISPLAY_AR_16_9,
|
|
||||||
DISPLAY_AR_20_9,
|
|
||||||
DISPLAY_AR_RAW,
|
|
||||||
} DISPLAY_AR;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
DISPLAY_AR_MODE_PANSCAN = 0,
|
|
||||||
DISPLAY_AR_MODE_LETTERBOX,
|
|
||||||
DISPLAY_AR_MODE_NONE,
|
|
||||||
DISPLAY_AR_MODE_PANSCAN2
|
|
||||||
} DISPLAY_AR_MODE;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
VIDEO_DB_DR_NEITHER = 0,
|
|
||||||
VIDEO_DB_ON,
|
|
||||||
VIDEO_DB_DR_BOTH
|
|
||||||
} VIDEO_DB_DR;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
VIDEO_PLAY_STILL = 0,
|
|
||||||
VIDEO_PLAY_CLIP,
|
|
||||||
VIDEO_PLAY_TRICK,
|
|
||||||
VIDEO_PLAY_MOTION,
|
|
||||||
VIDEO_PLAY_MOTION_NO_SYNC
|
|
||||||
} VIDEO_PLAY_MODE;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
VIDEO_STD_NTSC,
|
|
||||||
VIDEO_STD_SECAM,
|
|
||||||
VIDEO_STD_PAL,
|
|
||||||
VIDEO_STD_480P,
|
|
||||||
VIDEO_STD_576P,
|
|
||||||
VIDEO_STD_720P60,
|
|
||||||
VIDEO_STD_1080I60,
|
|
||||||
VIDEO_STD_720P50,
|
|
||||||
VIDEO_STD_1080I50,
|
|
||||||
VIDEO_STD_1080P30,
|
|
||||||
VIDEO_STD_1080P24,
|
|
||||||
VIDEO_STD_1080P25,
|
|
||||||
VIDEO_STD_AUTO,
|
|
||||||
VIDEO_STD_1080P50, /* SPARK only */
|
|
||||||
VIDEO_STD_MAX
|
|
||||||
} VIDEO_STD;
|
|
||||||
|
|
||||||
/* 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
|
|
||||||
{
|
|
||||||
friend class cDemux;
|
|
||||||
friend class cPlayback;
|
|
||||||
private:
|
|
||||||
/* video device */
|
|
||||||
int fd;
|
|
||||||
/* apparently we cannot query the driver's state
|
|
||||||
=> remember it */
|
|
||||||
video_play_state_t playstate;
|
|
||||||
int /*vidDispMode_t*/ croppingMode;
|
|
||||||
int /*vidOutFmt_t*/ outputformat;
|
|
||||||
int scartvoltage;
|
|
||||||
|
|
||||||
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;
|
|
||||||
int video_standby;
|
|
||||||
int64_t GetPTS(void);
|
|
||||||
|
|
||||||
void openDevice(void);
|
|
||||||
void closeDevice(void);
|
|
||||||
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(int x = 0 /*vidDispMode_t x = VID_DISPMODE_NORM*/);
|
|
||||||
|
|
||||||
/* get play state */
|
|
||||||
int getPlayState(void);
|
|
||||||
|
|
||||||
/* blank on freeze */
|
|
||||||
int getBlank(void);
|
|
||||||
int setBlank(int enable);
|
|
||||||
|
|
||||||
/* change video play state. Parameters are all unused. */
|
|
||||||
int Start(void *PcrChannel = NULL, unsigned short PcrPid = 0, unsigned short VideoPid = 0, void *x = NULL);
|
|
||||||
int Stop(bool blank = true);
|
|
||||||
bool Pause(void);
|
|
||||||
|
|
||||||
/* set video_system */
|
|
||||||
int SetVideoSystem(int video_system, bool remember = true);
|
|
||||||
int SetStreamType(VIDEO_FORMAT type);
|
|
||||||
void SetSyncMode(AVSYNC_TYPE mode);
|
|
||||||
bool SetCECMode(VIDEO_HDMI_CEC_MODE) { return true; };
|
|
||||||
void SetCECAutoView(bool) { return; };
|
|
||||||
void SetCECAutoStandby(bool) { return; };
|
|
||||||
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; };
|
|
||||||
void VideoParamWatchdog(void);
|
|
||||||
void setContrast(int val);
|
|
||||||
void SetVideoMode(analog_mode_t mode);
|
|
||||||
void SetDBDR(int) { return; };
|
|
||||||
void SetAudioHandle(void *) { return; };
|
|
||||||
void SetAutoModes(int [VIDEO_STD_MAX]) { return; };
|
|
||||||
int OpenVBI(int) { return 0; };
|
|
||||||
int CloseVBI(void) { return 0; };
|
|
||||||
int StartVBI(unsigned short) { return 0; };
|
|
||||||
int StopVBI(void) { return 0; };
|
|
||||||
void SetDemux(cDemux *dmx);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // __VIDEO_LIB_H__
|
|
Reference in New Issue
Block a user