first preliminary AZzbox ME support

TODO: some code is very similar to SPARK (record and pwrmngr
are just symlinked, dmx is almost identical). Reduce duplication
by factoring out DVBAPI code into an extra directory.
* what works: audio, video, demux
* what probably doesn't work or is untested: record
* what very likely doesn't work: playback
Playback is just copied over from aztrino and made to compile.
If you are lucky, it just segfaults :-)


Origin commit data
------------------
Branch: master
Commit: 0ac7346489
Author: Stefan Seyfried <seife@tuxbox-git.slipkontur.de>
Date: 2012-06-18 (Mon, 18 Jun 2012)



------------------
This commit was generated by Migit
This commit is contained in:
Stefan Seyfried
2012-06-18 14:43:59 +02:00
parent ce7c2cc049
commit e6450f7f08
29 changed files with 2602 additions and 2 deletions

1
.gitignore vendored
View File

@@ -12,6 +12,7 @@
/libeplayer3/Makefile.in /libeplayer3/Makefile.in
/libspark/Makefile.in /libspark/Makefile.in
/libtriple/Makefile.in /libtriple/Makefile.in
/azbox/Makefile.in
/ltmain.sh /ltmain.sh
/missing /missing
/Makefile.in /Makefile.in

View File

@@ -30,6 +30,17 @@ libstb_hal_a_LIBADD += \
libtriple/record_td.o \ libtriple/record_td.o \
libtriple/video_td.o libtriple/video_td.o
endif endif
if BOXTYPE_AZBOX
SUBDIRS += azbox
libstb_hal_a_LIBADD += \
azbox/audio.o \
azbox/dmx.o \
azbox/init.o \
azbox/playback.o \
azbox/pwrmngr.o \
azbox/record.o \
azbox/video.o
endif
if BOXTYPE_SPARK if BOXTYPE_SPARK
SUBDIRS += libspark libeplayer3 SUBDIRS += libspark libeplayer3
libstb_hal_a_LIBADD += \ libstb_hal_a_LIBADD += \

View File

@@ -266,9 +266,9 @@ _TUXBOX_APPS_LIB_SYMBOL($1,$2,$3,WARN)
AC_DEFUN([TUXBOX_BOXTYPE],[ AC_DEFUN([TUXBOX_BOXTYPE],[
AC_ARG_WITH(boxtype, AC_ARG_WITH(boxtype,
[ --with-boxtype valid values: dbox2,tripledragon,dreambox,ipbox,coolstream,spark,generic], [ --with-boxtype valid values: dbox2,tripledragon,dreambox,ipbox,coolstream,spark,azbox,generic],
[case "${withval}" in [case "${withval}" in
dbox2|dreambox|ipbox|tripledragon|coolstream|spark|generic) dbox2|dreambox|ipbox|tripledragon|coolstream|spark|azbox|generic)
BOXTYPE="$withval" BOXTYPE="$withval"
;; ;;
dm*) dm*)
@@ -308,6 +308,7 @@ AC_ARG_WITH(boxmodel,
AC_SUBST(BOXTYPE) AC_SUBST(BOXTYPE)
AC_SUBST(BOXMODEL) AC_SUBST(BOXMODEL)
AM_CONDITIONAL(BOXTYPE_AZBOX, test "$BOXTYPE" = "azbox")
AM_CONDITIONAL(BOXTYPE_DBOX2, test "$BOXTYPE" = "dbox2") AM_CONDITIONAL(BOXTYPE_DBOX2, test "$BOXTYPE" = "dbox2")
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")
@@ -329,6 +330,8 @@ AM_CONDITIONAL(BOXMODEL_IP400,test "$BOXMODEL" = "ip400")
if test "$BOXTYPE" = "dbox2"; then if test "$BOXTYPE" = "dbox2"; then
AC_DEFINE(HAVE_DBOX_HARDWARE, 1, [building for a dbox2]) AC_DEFINE(HAVE_DBOX_HARDWARE, 1, [building for a dbox2])
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

18
azbox/Makefile.am Normal file
View File

@@ -0,0 +1,18 @@
INCLUDES = \
-I$(top_srcdir)/common
# this library is not used for linking, so call it libdummy...
noinst_LIBRARIES = libdummy.a
AM_CXXFLAGS = -fno-rtti -fno-exceptions -fno-strict-aliasing
AM_LDFLAGS = -lpthread
libdummy_a_SOURCES = \
dmx.cpp \
video.cpp \
audio.cpp \
init.cpp \
playback.cpp \
pwrmngr.cpp \
record.cpp

389
azbox/audio.cpp Normal file
View File

@@ -0,0 +1,389 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <linux/dvb/audio.h>
#include "audio_lib.h"
#include "lt_debug.h"
#define AUDIO_DEVICE "/dev/dvb/adapter0/audio0"
#define lt_debug(args...) _lt_debug(TRIPLE_DEBUG_AUDIO, this, args)
#define lt_info(args...) _lt_info(TRIPLE_DEBUG_AUDIO, this, args)
#include <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)
{
lt_debug("%s\n", __func__);
if (fd < 0)
{
if ((fd = open(AUDIO_DEVICE, O_RDWR)) < 0)
lt_info("openDevice: open failed (%m)\n");
fcntl(fd, F_SETFD, FD_CLOEXEC);
do_mute(true, false);
}
else
lt_info("openDevice: already open (fd = %d)\n", fd);
}
void cAudio::closeDevice(void)
{
lt_debug("%s\n", __func__);
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)
{
lt_debug("%s(%d, %d)\n", __func__, enable, remember);
if (remember)
Muted = enable;
if (ioctl(fd, AUDIO_SET_MUTE, enable) < 0 )
lt_info("%s: AUDIO_SET_MUTE failed (%m)\n", __func__);
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)
{
lt_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)
lt_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)
lt_info("%s: AUDIO_SET_MIXER failed (%m)\n", __func__);
return 0;
}
int cAudio::Start(void)
{
lt_debug("%s\n", __func__);
int ret;
ioctl(fd, AUDIO_CONTINUE);
ret = ioctl(fd, AUDIO_PLAY);
return ret;
}
int cAudio::Stop(void)
{
lt_debug("%s\n", __func__);
return ioctl(fd, AUDIO_STOP);
}
bool cAudio::Pause(bool /*Pcm*/)
{
return true;
};
void cAudio::SetSyncMode(AVSYNC_TYPE Mode)
{
lt_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;
lt_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)
lt_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");
lt_debug("%s ch %d srate %d bits %d le %d\n", __FUNCTION__, ch, srate, bits, little_endian);
if (clipfd >= 0) {
lt_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)
lt_info("%s: DSP_DEVICE is set (%s) but cannot be opened,"
" fall back to /dev/dsp1\n", __func__, dsp_dev);
dsp_dev = "/dev/dsp1";
}
lt_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);
if (clipfd < 0) {
lt_info("%s open %s: %m\n", dsp_dev, __FUNCTION__);
return -1;
}
fcntl(clipfd, F_SETFD, FD_CLOEXEC);
/* no idea if we ever get little_endian == 0 */
if (little_endian)
fmt = AFMT_S16_BE;
else
fmt = AFMT_S16_LE;
if (ioctl(clipfd, SNDCTL_DSP_SETFMT, &fmt))
perror("SNDCTL_DSP_SETFMT");
if (ioctl(clipfd, SNDCTL_DSP_CHANNELS, &ch))
perror("SNDCTL_DSP_CHANNELS");
if (ioctl(clipfd, SNDCTL_DSP_SPEED, &srate))
perror("SNDCTL_DSP_SPEED");
if (ioctl(clipfd, SNDCTL_DSP_RESET))
perror("SNDCTL_DSP_RESET");
if (!mix_dev)
return 0;
mixer_fd = open(mix_dev, O_RDWR);
if (mixer_fd < 0) {
lt_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) {
lt_info("%s: SOUND_MIXER_READ_DEVMASK %m\n", __func__);
devmask = 0;
}
if (ioctl(mixer_fd, SOUND_MIXER_READ_STEREODEVS, &stereo) == -1) {
lt_info("%s: SOUND_MIXER_READ_STEREODEVS %m\n", __func__);
stereo = 0;
}
usable = devmask & stereo;
if (usable == 0) {
lt_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... */
lt_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);
lt_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;
// lt_debug("cAudio::%s\n", __FUNCTION__);
if (clipfd <= 0) {
lt_info("%s: clipfd not yet opened\n", __FUNCTION__);
return -1;
}
ret = write(clipfd, buffer, size);
if (ret < 0)
lt_info("%s: write error (%m)\n", __FUNCTION__);
return ret;
};
int cAudio::StopClip()
{
lt_debug("%s\n", __FUNCTION__);
if (clipfd <= 0) {
lt_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)
{
lt_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*/)
{
lt_debug("%s\n", __FUNCTION__);
};
void cAudio::SetHdmiDD(bool enable)
{
lt_debug("%s %d\n", __func__, enable);
};
void cAudio::SetSpdifDD(bool enable)
{
lt_debug("%s %d\n", __func__, enable);
setBypassMode(!enable);
};
void cAudio::ScheduleMute(bool On)
{
lt_debug("%s %d\n", __FUNCTION__, On);
};
void cAudio::EnableAnalogOut(bool enable)
{
lt_debug("%s %d\n", __FUNCTION__, enable);
};
#define AUDIO_BYPASS_ON 0
#define AUDIO_BYPASS_OFF 1
void cAudio::setBypassMode(bool disable)
{
lt_debug("%s %d\n", __func__, disable);
int mode = disable ? AUDIO_BYPASS_OFF : AUDIO_BYPASS_ON;
if (ioctl(fd, AUDIO_SET_BYPASS_MODE, mode) < 0)
lt_info("%s AUDIO_SET_BYPASS_MODE %d: %m\n", __func__, mode);
return;
}

97
azbox/audio_lib.h Normal file
View File

@@ -0,0 +1,97 @@
/* public header file */
#ifndef _AUDIO_LIB_H_
#define _AUDIO_LIB_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);
#define AVSYNC_TYPE int
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

1
azbox/cs_api.h Symbolic link
View File

@@ -0,0 +1 @@
../libspark/cs_api.h

490
azbox/dmx.cpp Normal file
View File

@@ -0,0 +1,490 @@
#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 "dmx_lib.h"
#include "lt_debug.h"
/* Ugh... see comment in destructor for details... */
#include "video_lib.h"
extern cVideo *videoDecoder;
#define lt_debug(args...) _lt_debug(TRIPLE_DEBUG_DEMUX, this, args)
#define lt_info(args...) _lt_info(TRIPLE_DEBUG_DEMUX, this, args)
#define dmx_err(_errfmt, _errstr, _revents) do { \
uint16_t _pid = (uint16_t)-1; uint16_t _f = 0;\
if (dmx_type == DMX_PES_CHANNEL) { \
_pid = p_flt.pid; \
} else if (dmx_type == DMX_PSI_CHANNEL) { \
_pid = s_flt.pid; _f = s_flt.filter.filter[0]; \
}; \
lt_info("%s " _errfmt " fd:%d, ev:0x%x %s pid:0x%04hx flt:0x%02hx\n", \
__func__, _errstr, fd, _revents, DMX_T[dmx_type], _pid, _f); \
} while(0);
cDemux *videoDemux = NULL;
cDemux *audioDemux = NULL;
//cDemux *pcrDemux = NULL;
static const char *DMX_T[] = {
"DMX_INVALID",
"DMX_VIDEO",
"DMX_AUDIO",
"DMX_PES",
"DMX_PSI",
"DMX_PIP",
"DMX_TP",
"DMX_PCR"
};
/* map the device numbers. for now only demux0 is used */
static const char *devname[] = {
"/dev/dvb/adapter0/demux0",
"/dev/dvb/adapter0/demux0",
"/dev/dvb/adapter0/demux0"
};
/* uuuugly */
static int dmx_tp_count = 0;
#define MAX_TS_COUNT 8
cDemux::cDemux(int n)
{
if (n < 0 || n > 2)
{
lt_info("%s ERROR: n invalid (%d)\n", __FUNCTION__, n);
num = 0;
}
else
num = n;
fd = -1;
measure = false;
last_measure = 0;
last_data = 0;
}
cDemux::~cDemux()
{
lt_debug("%s #%d fd: %d\n", __FUNCTION__, num, fd);
Close();
/* 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;
if (fd > -1)
lt_info("%s FD ALREADY OPENED? fd = %d\n", __FUNCTION__, fd);
fd = open(devname[devnum], flags);
if (fd < 0)
{
lt_info("%s %s: %m\n", __FUNCTION__, devname[devnum]);
return false;
}
fcntl(fd, F_SETFD, FD_CLOEXEC);
lt_debug("%s #%d pes_type: %s(%d), uBufferSize: %d fd: %d\n", __func__,
num, DMX_T[pes_type], pes_type, uBufferSize, fd);
dmx_type = pes_type;
#if 0
if (!pesfds.empty())
{
lt_info("%s ERROR! pesfds not empty!\n", __FUNCTION__); /* TODO: error handling */
return false;
}
#endif
int n = DMX_SOURCE_FRONT0;
if (ioctl(fd, DMX_SET_SOURCE, &n) < 0)
lt_info("%s DMX_SET_SOURCE failed!\n", __func__);
if (uBufferSize > 0)
{
/* probably uBufferSize == 0 means "use default size". TODO: find a reasonable default */
if (ioctl(fd, DMX_SET_BUFFER_SIZE, uBufferSize) < 0)
lt_info("%s DMX_SET_BUFFER_SIZE failed (%m)\n", __func__);
}
buffersize = uBufferSize;
return true;
}
void cDemux::Close(void)
{
lt_debug("%s #%d, fd = %d\n", __FUNCTION__, num, fd);
if (fd < 0)
{
lt_info("%s #%d: not open!\n", __FUNCTION__, num);
return;
}
for (std::vector<pes_pids>::const_iterator i = pesfds.begin(); i != pesfds.end(); ++i)
{
lt_debug("%s stopping and closing demux fd %d pid 0x%04x\n", __FUNCTION__, (*i).fd, (*i).pid);
if (ioctl((*i).fd, DMX_STOP) < 0)
perror("DEMUX_STOP");
if (close((*i).fd) < 0)
perror("close");
}
pesfds.clear();
ioctl(fd, DMX_STOP);
close(fd);
fd = -1;
if (measure)
return;
if (dmx_type == DMX_TP_CHANNEL)
{
dmx_tp_count--;
if (dmx_tp_count < 0)
{
lt_info("%s dmx_tp_count < 0!!\n", __func__);
dmx_tp_count = 0;
}
}
}
bool cDemux::Start(bool)
{
lt_debug("%s #%d fd: %d type: %s\n", __func__, num, fd, DMX_T[dmx_type]);
if (fd < 0)
{
lt_info("%s #%d: not open!\n", __FUNCTION__, num);
return false;
}
for (std::vector<pes_pids>::const_iterator i = pesfds.begin(); i != pesfds.end(); ++i)
{
lt_debug("%s starting demux fd %d pid 0x%04x\n", __FUNCTION__, (*i).fd, (*i).pid);
if (ioctl((*i).fd, DMX_START) < 0)
perror("DMX_START");
}
ioctl(fd, DMX_START);
return true;
}
bool cDemux::Stop(void)
{
lt_debug("%s #%d fd: %d type: %s\n", __func__, num, fd, DMX_T[dmx_type]);
if (fd < 0)
{
lt_info("%s #%d: not open!\n", __FUNCTION__, num);
return false;
}
for (std::vector<pes_pids>::const_iterator i = pesfds.begin(); i != pesfds.end(); ++i)
{
lt_debug("%s stopping demux fd %d pid 0x%04x\n", __FUNCTION__, (*i).fd, (*i).pid);
if (ioctl((*i).fd, DMX_STOP) < 0)
perror("DMX_STOP");
}
ioctl(fd, DMX_STOP);
return true;
}
int cDemux::Read(unsigned char *buff, int len, int timeout)
{
#if 0
if (len != 4095 && timeout != 100)
fprintf(stderr, "cDemux::%s #%d fd: %d type: %s len: %d timeout: %d\n",
__FUNCTION__, num, fd, DMX_T[dmx_type], len, timeout);
#endif
int rc;
struct pollfd ufds;
ufds.fd = fd;
ufds.events = POLLIN|POLLPRI|POLLERR;
ufds.revents = 0;
if (timeout > 0)
{
retry:
rc = ::poll(&ufds, 1, timeout);
if (!rc)
return 0; // timeout
else if (rc < 0)
{
dmx_err("poll: %s,", strerror(errno), 0)
//lt_info("%s poll: %m\n", __FUNCTION__);
/* happens, when running under gdb... */
if (errno == EINTR)
goto retry;
return -1;
}
#if 0
if (ufds.revents & POLLERR) /* POLLERR means buffer error, i.e. buffer overflow */
{
dmx_err("received %s,", "POLLERR", ufds.revents);
/* this seems to happen sometimes at recording start, without bad effects */
return 0;
}
#endif
if (ufds.revents & POLLHUP) /* we get POLLHUP if e.g. a too big DMX_BUFFER_SIZE was set */
{
dmx_err("received %s,", "POLLHUP", ufds.revents);
return -1;
}
if (!(ufds.revents & POLLIN)) /* we requested POLLIN but did not get it? */
{
dmx_err("received %s, please report!", "POLLIN", ufds.revents);
return 0;
}
}
rc = ::read(fd, buff, len);
//fprintf(stderr, "fd %d ret: %d\n", fd, rc);
if (rc < 0)
dmx_err("read: %s", strerror(errno), 0);
return rc;
}
bool cDemux::sectionFilter(unsigned short pid, const unsigned char * const filter,
const unsigned char * const mask, int len, int timeout,
const unsigned char * const negmask)
{
int length = len;
memset(&s_flt, 0, sizeof(s_flt));
if (len > DMX_FILTER_SIZE)
{
lt_info("%s #%d: len too long: %d, DMX_FILTER_SIZE %d\n", __func__, num, len, DMX_FILTER_SIZE);
length = DMX_FILTER_SIZE;
}
s_flt.pid = pid;
s_flt.timeout = timeout;
memcpy(s_flt.filter.filter, filter, len);
memcpy(s_flt.filter.mask, mask, len);
if (negmask != NULL)
memcpy(s_flt.filter.mode, negmask, len);
s_flt.flags = DMX_IMMEDIATE_START|DMX_CHECK_CRC;
int to = 0;
switch (filter[0]) {
case 0x00: /* program_association_section */
to = 2000;
break;
case 0x01: /* conditional_access_section */
to = 6000;
break;
case 0x02: /* program_map_section */
to = 1500;
break;
case 0x03: /* transport_stream_description_section */
to = 10000;
break;
/* 0x04 - 0x3F: reserved */
case 0x40: /* network_information_section - actual_network */
to = 10000;
break;
case 0x41: /* network_information_section - other_network */
to = 15000;
break;
case 0x42: /* service_description_section - actual_transport_stream */
to = 10000;
break;
/* 0x43 - 0x45: reserved for future use */
case 0x46: /* service_description_section - other_transport_stream */
to = 10000;
break;
/* 0x47 - 0x49: reserved for future use */
case 0x4A: /* bouquet_association_section */
to = 11000;
break;
/* 0x4B - 0x4D: reserved for future use */
case 0x4E: /* event_information_section - actual_transport_stream, present/following */
to = 2000;
break;
case 0x4F: /* event_information_section - other_transport_stream, present/following */
to = 10000;
break;
/* 0x50 - 0x5F: event_information_section - actual_transport_stream, schedule */
/* 0x60 - 0x6F: event_information_section - other_transport_stream, schedule */
case 0x70: /* time_date_section */
s_flt.flags &= ~DMX_CHECK_CRC; /* section has no CRC */
//s_flt.pid = 0x0014;
to = 30000;
break;
case 0x71: /* running_status_section */
s_flt.flags &= ~DMX_CHECK_CRC; /* section has no CRC */
to = 0;
break;
case 0x72: /* stuffing_section */
s_flt.flags &= ~DMX_CHECK_CRC; /* section has no CRC */
to = 0;
break;
case 0x73: /* time_offset_section */
//s_flt.pid = 0x0014;
to = 30000;
break;
/* 0x74 - 0x7D: reserved for future use */
case 0x7E: /* discontinuity_information_section */
s_flt.flags &= ~DMX_CHECK_CRC; /* section has no CRC */
to = 0;
break;
case 0x7F: /* selection_information_section */
to = 0;
break;
/* 0x80 - 0x8F: ca_message_section */
/* 0x90 - 0xFE: user defined */
/* 0xFF: reserved */
default:
break;
// return -1;
}
/* the negmask == NULL is a hack: the users of negmask are PMT-update
* and sectionsd EIT-Version change. And they really want no timeout
* if timeout == 0 instead of "default timeout" */
if (timeout == 0 && negmask == NULL)
s_flt.timeout = to;
lt_debug("%s #%d pid:0x%04hx fd:%d type:%s len:%d to:%d flags:%x flt[0]:%02x\n", __func__, num,
pid, fd, DMX_T[dmx_type], len, s_flt.timeout,s_flt.flags, s_flt.filter.filter[0]);
#if 0
fprintf(stderr,"filt: ");for(int i=0;i<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;
return true;
}
bool cDemux::pesFilter(const unsigned short pid)
{
/* 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;
lt_debug("%s #%d pid: 0x%04hx fd: %d type: %s\n", __FUNCTION__, num, pid, fd, DMX_T[dmx_type]);
memset(&p_flt, 0, sizeof(p_flt));
p_flt.pid = pid;
p_flt.output = DMX_OUT_DECODER;
p_flt.input = DMX_IN_FRONTEND;
switch (dmx_type) {
case DMX_PCR_ONLY_CHANNEL:
p_flt.pes_type = DMX_PES_PCR;
break;
case DMX_AUDIO_CHANNEL:
p_flt.pes_type = DMX_PES_AUDIO;
break;
case DMX_VIDEO_CHANNEL:
p_flt.pes_type = DMX_PES_VIDEO;
break;
case DMX_PES_CHANNEL:
p_flt.pes_type = DMX_PES_OTHER;
p_flt.output = DMX_OUT_TAP;
break;
case DMX_TP_CHANNEL:
p_flt.pes_type = DMX_PES_OTHER;
p_flt.output = DMX_OUT_TSDEMUX_TAP;
break;
default:
lt_info("%s #%d invalid dmx_type %d!\n", __func__, num, dmx_type);
return false;
}
return (ioctl(fd, DMX_SET_PES_FILTER, &p_flt) >= 0);
}
void cDemux::SetSyncMode(AVSYNC_TYPE /*mode*/)
{
lt_debug("%s #%d\n", __FUNCTION__, num);
}
void *cDemux::getBuffer()
{
lt_debug("%s #%d\n", __FUNCTION__, num);
return NULL;
}
void *cDemux::getChannel()
{
lt_debug("%s #%d\n", __FUNCTION__, num);
return NULL;
}
bool cDemux::addPid(unsigned short Pid)
{
lt_debug("%s: pid 0x%04hx\n", __func__, Pid);
pes_pids pfd;
int ret;
struct dmx_pes_filter_params p;
if (dmx_type != DMX_TP_CHANNEL)
{
lt_info("%s pes_type %s not implemented yet! pid=%hx\n", __FUNCTION__, DMX_T[dmx_type], Pid);
return false;
}
if (fd == -1)
lt_info("%s bucketfd not yet opened? pid=%hx\n", __FUNCTION__, Pid);
ret = (ioctl(fd, DMX_ADD_PID, &Pid));
if (ret < 0)
lt_info("%s: DMX_ADD_PID (%m)\n", __func__);
return (ret != -1);
}
void cDemux::removePid(unsigned short Pid)
{
if (dmx_type != DMX_TP_CHANNEL)
{
lt_info("%s pes_type %s not implemented yet! pid=%hx\n", __FUNCTION__, DMX_T[dmx_type], Pid);
return;
}
for (std::vector<pes_pids>::iterator i = pesfds.begin(); i != pesfds.end(); ++i)
{
if ((*i).pid == Pid) {
lt_debug("removePid: removing demux fd %d pid 0x%04x\n", (*i).fd, Pid);
if (ioctl((*i).fd, DMX_STOP) < 0)
perror("DMX_STOP");
if (close((*i).fd) < 0)
perror("close");
pesfds.erase(i);
return; /* TODO: what if the same PID is there multiple times */
}
}
lt_info("%s pid 0x%04x not found\n", __FUNCTION__, Pid);
}
void cDemux::getSTC(int64_t * STC)
{
/* apparently I can only get the PTS of the video decoder,
* but that's good enough for dvbsub */
lt_debug("%s #%d\n", __func__, num);
int64_t pts = 0;
if (videoDecoder)
pts = videoDecoder->GetPTS();
*STC = pts;
}
int cDemux::getUnit(void)
{
lt_debug("%s #%d\n", __FUNCTION__, num);
/* just guessed that this is the right thing to do.
right now this is only used by the CA code which is stubbed out
anyway */
return num;
}

1
azbox/dmx_cs.h Normal file
View File

@@ -0,0 +1 @@
#include "dmx_lib.h"

66
azbox/dmx_lib.h Normal file
View File

@@ -0,0 +1,66 @@
#ifndef __DEMUX_TD_H
#define __DEMUX_TD_H
#include <cstdlib>
#include <vector>
#include <inttypes.h>
#include <sys/ioctl.h>
#include <linux/dvb/dmx.h>
typedef enum
{
DMX_INVALID = 0,
DMX_VIDEO_CHANNEL = 1,
DMX_AUDIO_CHANNEL,
DMX_PES_CHANNEL,
DMX_PSI_CHANNEL,
DMX_PIP_CHANNEL,
DMX_TP_CHANNEL,
DMX_PCR_ONLY_CHANNEL
} DMX_CHANNEL_TYPE;
typedef struct
{
int fd;
unsigned short pid;
} pes_pids;
class cDemux
{
private:
int num;
int fd;
int buffersize;
bool measure;
uint64_t last_measure, last_data;
DMX_CHANNEL_TYPE dmx_type;
std::vector<pes_pids> pesfds;
struct dmx_sct_filter_params s_flt;
struct dmx_pes_filter_params p_flt;
public:
bool Open(DMX_CHANNEL_TYPE pes_type, void * x = NULL, int y = 0);
void Close(void);
bool Start(bool record = false);
bool Stop(void);
int Read(unsigned char *buff, int len, int Timeout = 0);
bool sectionFilter(unsigned short pid, const unsigned char * const filter, const unsigned char * const mask, int len, int Timeout = 0, const unsigned char * const negmask = NULL);
bool pesFilter(const unsigned short pid);
#define AVSYNC_TYPE int
void SetSyncMode(AVSYNC_TYPE mode);
void * getBuffer();
void * getChannel();
DMX_CHANNEL_TYPE getChannelType(void) { return dmx_type; };
bool addPid(unsigned short pid);
void getSTC(int64_t * STC);
int getUnit(void);
// TD only functions
int getFD(void) { return fd; }; /* needed by cPlayback class */
void removePid(unsigned short Pid); /* needed by cRecord class */
std::vector<pes_pids> getPesPids(void) { return pesfds; };
//
cDemux(int num = 0);
~cDemux();
};
#endif //__DEMUX_H

83
azbox/e2mruainclude.h Normal file
View File

@@ -0,0 +1,83 @@
//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;

21
azbox/init.cpp Normal file
View File

@@ -0,0 +1,21 @@
#include <unistd.h>
#include "init_lib.h"
#include "lt_debug.h"
#define lt_debug(args...) _lt_debug(TRIPLE_DEBUG_INIT, NULL, args)
#define lt_info(args...) _lt_info(TRIPLE_DEBUG_INIT, NULL, args)
static bool initialized = false;
void init_td_api()
{
if (!initialized)
lt_debug_init();
lt_info("%s begin, initialized=%d, debug=0x%02x\n", __func__, (int)initialized, debuglevel);
initialized = true;
}
void shutdown_td_api()
{
lt_info("%s, initialized = %d\n", __func__, (int)initialized);
initialized = false;
}

5
azbox/init_lib.h Normal file
View File

@@ -0,0 +1,5 @@
#ifndef __INIT_TD_H
#define __INIT_TD_H
void init_td_api();
void shutdown_td_api();
#endif

499
azbox/playback.cpp Normal file
View File

@@ -0,0 +1,499 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sstream>
#include <sys/stat.h>
#define FIFO_CMD "/tmp/rmfp.cmd"
#define FIFO_IN "/tmp/rmfp.in"
#define FIFO_OUT "/tmp/rmfp.out"
#define FIFO_EVENT "/tmp/rmfp.event"
#include "playback.h"
extern "C"{
#include "e2mruainclude.h"
}
static const char * FILENAME = "playback_cs.cpp";
void cPlayback::RuaThread()
{
printf("Starting RUA thread\n");
//Watch for the space at the end
std::string base = "/usr/bin/rmfp_player -dram 1 -ve 1 -waitexit ";
std::string filename(mfilename);
std::string file = '"' + filename + '"';
std::string final = base + file;
if ( setduration == 1 && mduration != 0)
{
mduration *= 60000;
std::stringstream duration;
duration << mduration;
final = base + "-duration " + duration.str() + " " + file;
}
system(final.c_str());
printf("Terminating RUA thread\n");
thread_active = 0;
playing = false;
eof_reached = 1;
pthread_exit(NULL);
}
/* helper function to call the cpp thread loop */
void* execute_rua_thread(void *c)
{
cPlayback *obj=(cPlayback*)c;
printf("Executing RUA Thread\n");
obj->RuaThread();
free(obj);
return NULL;
}
void cPlayback::EventThread()
{
printf("Starting Event thread\n");
thread_active = 1;
eof_reached = 0;
while (thread_active == 1)
{
struct timeval tv;
fd_set readfds;
int retval;
tv.tv_sec = 1;
tv.tv_usec = 0;
FD_ZERO(&readfds);
FD_SET(fd_event, &readfds);
retval = select(fd_event + 1, &readfds, NULL, NULL, &tv);
//printf("retval is %i\n", retval);
if (retval)
{
char eventstring[4];
int event;
read(fd_event, &eventstring, 3);
eventstring[3] = '\0';
event = atoi(eventstring);
printf("Got event message %i\n", event);
switch(event)
{
case EVENT_MSG_FDOPEN:
fd_cmd = open(FIFO_CMD, O_WRONLY);
fd_in = open(FIFO_IN, O_WRONLY);
printf("Message FD Opened %i", fd_in);
break;
case EVENT_MSG_PLAYBACK_STARTED:
printf("Got playing event \n");
playing = true;
break;
case EVENT_MSG_EOS:
printf("Got EOF event \n");
eof_reached = 1;
break;
}
}
usleep(100000);
}
printf("Terminating Event thread\n");
playing = false;
pthread_exit(NULL);
}
/* helper function to call the cpp thread loop */
void* execute_event_thread(void *c)
{
cPlayback *obj=(cPlayback*)c;
printf("Executing RUA Thread\n");
obj->EventThread();
return NULL;
}
//Used by Fileplay
bool cPlayback::Open(playmode_t PlayMode)
{
const char *aPLAYMODE[] = {
"PLAYMODE_TS",
"PLAYMODE_FILE"
};
setduration = 0;
if (PlayMode == 0)
{
printf("RECORDING PLAYING BACK\n");
setduration = 1;
}
printf("%s:%s - PlayMode=%s\n", FILENAME, __FUNCTION__, aPLAYMODE[PlayMode]);
//Making Fifo's for message pipes
mknod(FIFO_CMD, S_IFIFO | 0666, 0);
mknod(FIFO_IN, S_IFIFO | 0666, 0);
mknod(FIFO_OUT, S_IFIFO | 0666, 0);
mknod(FIFO_EVENT, S_IFIFO | 0666, 0);
//Open pipes we read from. The fd_in pipe will be created once test_rmfp has been started
fd_out = open(FIFO_OUT, O_RDONLY | O_NONBLOCK);
fd_event = open(FIFO_EVENT, O_RDONLY | O_NONBLOCK);
return 0;
}
//Used by Fileplay
void cPlayback::Close(void)
{
printf("%s:%s\n", FILENAME, __FUNCTION__);
//Dagobert: movieplayer does not call stop, it calls close ;)
Stop();
}
//Used by Fileplay
bool cPlayback::Start(char * filename, unsigned short vpid, int vtype, unsigned short apid, bool ac3, int duration)
{
bool ret = true;
printf("%s:%s - filename=%s vpid=%u vtype=%d apid=%u ac3=%d duration=%i\n",
FILENAME, __FUNCTION__, filename, vpid, vtype, apid, ac3, duration);
//create playback path
mAudioStream=0;
mfilename = filename;
mduration = duration;
if (pthread_create(&rua_thread, 0, execute_rua_thread, this) != 0)
{
printf("[movieplayer]: error creating file_thread! (out of memory?)\n");
ret = false;
}
if (pthread_create(&event_thread, 0, execute_event_thread, this) != 0)
{
printf("[movieplayer]: error creating file_thread! (out of memory?)\n");
ret = false;
}
return ret;
}
//Used by Fileplay
bool cPlayback::Stop(void)
{
printf("%s:%s playing %d %d\n", FILENAME, __FUNCTION__, playing, thread_active);
if(playing==false && thread_active == 0) return false;
msg = KEY_COMMAND_QUIT_ALL;
dprintf(fd_cmd, "%i", msg);
if (pthread_join(rua_thread, NULL))
{
printf("error joining rua thread\n");
}
if (pthread_join(event_thread, NULL))
{
printf("error joining event thread\n");
}
playing = false;
return true;
}
bool cPlayback::SetAPid(unsigned short pid, bool /*ac3*/)
{
printf("%s:%s pid %i\n", FILENAME, __FUNCTION__, pid);
if (pid != mAudioStream) {
msg = KEY_COMMAND_SWITCH_AUDIO;
dprintf(fd_cmd, "%i", msg);
dprintf(fd_in, "%i", pid);
mAudioStream = pid;
}
return true;
}
bool cPlayback::SetSPid(int pid)
{
printf("%s:%s pid %i\n", FILENAME, __FUNCTION__, pid);
if(pid!=mSubStream)
{
msg = KEY_COMMAND_SWITCH_SUBS;
dprintf(fd_cmd, "%i", msg);
dprintf(fd_in, "%i", pid);
mSubStream=pid;
}
return true;
}
bool cPlayback::SetSpeed(int speed)
{
printf("%s:%s playing %d speed %d\n", FILENAME, __FUNCTION__, playing, speed);
if(playing==false)
return false;
// int result = 0;
nPlaybackSpeed = speed;
if (speed > 1 || speed < 0)
{
msg = CUSTOM_COMMAND_TRICK_SEEK;
dprintf(fd_cmd, "%i", msg);
dprintf(fd_in, "%i", speed);
}
else if (speed == 0)
{
msg = KEY_COMMAND_PAUSE;
dprintf(fd_cmd, "%i", msg);
}
else
{
msg = KEY_COMMAND_PLAY;
dprintf(fd_cmd, "%i", msg);
}
// if (result != 0)
// {
// printf("returning false\n");
// return false;
// }
return true;
}
bool cPlayback::GetSpeed(int &/*speed*/) const
{
/* printf("%s:%s\n", FILENAME, __FUNCTION__);
speed = nPlaybackSpeed;
*/ return true;
}
// in milliseconds
bool cPlayback::GetPosition(int &position, int &duration)
{
printf("%s:%s %d %d\n", FILENAME, __FUNCTION__, position, duration);
//Azbox eof
if (eof_reached == 1)
{
position = -5;
duration = -5;
return true;
}
if(playing==false) return false;
//Position
char timestring[11];
msg = CUSTOM_COMMAND_GETPOSITION;
dprintf(fd_cmd, "%i", msg);
int n = 0;
while ( n <= 0 ) {
n = read(fd_out, &timestring, 100);
}
timestring[10] = '\0';
position = atoi(timestring);
//Duration
int length;
char durationstring[11];
msg = CUSTOM_COMMAND_GETLENGTH;
dprintf(fd_cmd, "%i", msg);
n = 0;
while ( n <= 0 ) {
n = read(fd_out, &durationstring, 10);
}
durationstring[10] = '\0';
length = atoi(durationstring);
if(length <= 0) {
duration = duration+1000;
} else {
duration = length;
}
return true;
}
bool cPlayback::SetPosition(int position, bool absolute)
{
printf("%s:%s %d\n", FILENAME, __FUNCTION__,position);
if(playing==false) return false;
int seconds;
if (absolute == true)
{
msg = KEY_COMMAND_SEEK_TO_TIME;
seconds = position / 1000;
dprintf(fd_cmd, "%i", msg);
dprintf(fd_in, "%i", seconds);
}
else
{
if (position > 0 )
{
msg = CUSTOM_COMMAND_SEEK_RELATIVE_FWD;
seconds = position / 1000;
dprintf(fd_cmd, "%i", msg);
dprintf(fd_in, "%i", seconds);
}
else if ( position < 0 )
{
msg = CUSTOM_COMMAND_SEEK_RELATIVE_BWD;
seconds = position / 1000;
seconds *= -1;
printf("sending seconds %i\n", seconds);
dprintf(fd_cmd, "%i", msg);
dprintf(fd_in, "%i", seconds);
}
}
return true;
}
void cPlayback::FindAllPids(uint16_t *apids, unsigned short *ac3flags, uint16_t *numpida, std::string *language)
{
printf("%s:%s\n", FILENAME, __FUNCTION__);
unsigned int audio_count = 0;
char audio_countstring[3];
msg = CUSTOM_COMMAND_AUDIO_COUNT;
dprintf(fd_cmd, "%i", msg);
int n = 0;
while ( n <= 0 ) {
n = read(fd_out, &audio_countstring, 2);
}
audio_countstring[2] = '\0';
audio_count = atoi(audio_countstring);
*numpida = audio_count;
if (audio_count > 0 )
{
for ( unsigned int audio_id = 0; audio_id < audio_count; audio_id++ )
{
char streamidstring[11];
char audio_lang[21];
msg = CUSTOM_COMMAND_GET_AUDIO_BY_ID;
dprintf(fd_cmd, "%i", msg);
dprintf(fd_in, "%i", audio_id);
n = 0;
while ( n <= 0 ) {
n = read(fd_out, &streamidstring, 10);
}
read(fd_out, &audio_lang, 20);
streamidstring[10] = '\0';
audio_lang[20] = '\0';
apids[audio_id] = atoi(streamidstring);
ac3flags[audio_id] = 0;
language[audio_id] = audio_lang;
}
}
}
void cPlayback::FindAllSPids(int *spids, uint16_t *numpids, std::string *language)
{
printf("%s:%s\n", FILENAME, __FUNCTION__);
unsigned int spu_count = 0;
char spu_countstring[3];
msg = CUSTOM_COMMAND_SUBS_COUNT;
dprintf(fd_cmd, "%i", msg);
int n = 0;
while ( n <= 0 ) {
n = read(fd_out, &spu_countstring, 2);
}
spu_countstring[2] = '\0';
spu_count = atoi(spu_countstring);
*numpids = spu_count;
if (spu_count > 0 )
{
for ( unsigned int spu_id = 0; spu_id < spu_count; spu_id++ )
{
//int streamid;
char streamidstring[11];
char spu_lang[21];
msg = CUSTOM_COMMAND_GET_SUB_BY_ID;
dprintf(fd_cmd, "%i", msg);
dprintf(fd_in, "%i", spu_id);
n = 0;
while ( n <= 0 ) {
n = read(fd_out, &streamidstring, 10);
}
read(fd_out, &spu_lang, 20);
streamidstring[10] = '\0';
spu_lang[20] = '\0';
spids[spu_id] = atoi(streamidstring);
language[spu_id] = spu_lang;
}
}
//Add streamid -1 to be able to disable subtitles
*numpids = spu_count + 1;
spids[spu_count] = -1;
language[spu_count] = "Disable";
}
cPlayback::cPlayback(int /*num*/)
{
printf("%s:%s\n", FILENAME, __FUNCTION__);
playing=false;
thread_active = 0;
eof_reached=0;
}
cPlayback::~cPlayback()
{
printf("%s:%s\n", FILENAME, __FUNCTION__);
}
bool cPlayback::IsEOF(void) const
{
// printf("%s:%s\n", FILENAME, __FUNCTION__);
return eof_reached;
}
int cPlayback::GetCurrPlaybackSpeed(void) const
{
printf("%s:%s\n", FILENAME, __FUNCTION__);
return nPlaybackSpeed;
}

80
azbox/playback.h Normal file
View File

@@ -0,0 +1,80 @@
#ifndef __PLAYBACK_H
#define __PLAYBACK_H
#include <string>
#include <stdint.h>
#ifndef CS_PLAYBACK_PDATA
typedef struct {
int nothing;
} CS_PLAYBACK_PDATA;
#endif
typedef enum {
PLAYMODE_TS = 0,
PLAYMODE_FILE,
} playmode_t;
class cPlayback
{
private:
int timeout;
pthread_cond_t read_cond;
pthread_mutex_t mutex;
CS_PLAYBACK_PDATA * privateData;
pthread_t rua_thread;
pthread_t event_thread;
bool enabled;
bool paused;
bool playing;
int unit;
int nPlaybackFD;
int video_type;
int nPlaybackSpeed;
int mSpeed;
int mAudioStream;
int mSubStream;
char* mfilename;
int thread_active;
int eof_reached;
int setduration;
int mduration;
playmode_t playMode;
//
public:
bool Open(playmode_t PlayMode);
void Close(void);
bool Start(char * filename, unsigned short vpid, int vtype, unsigned short apid, bool ac3, int duration);
bool Stop(void);
bool SetAPid(unsigned short pid, bool ac3);
bool SetSPid(int pid);
bool SetSpeed(int speed);
bool GetSpeed(int &speed) const;
bool GetPosition(int &position, int &duration);
bool SetPosition(int position, bool absolute = false);
bool IsEOF(void) const;
int GetCurrPlaybackSpeed(void) const;
void FindAllPids(uint16_t *apids, unsigned short *ac3flags, uint16_t *numpida, std::string *language);
void FindAllSPids(int *spids, uint16_t *numpids, std::string *language);
//
cPlayback(int num = 0);
~cPlayback();
void RuaThread();
void EventThread();
#if 0
/* not used */
bool GetOffset(off64_t &offset);
void PlaybackNotify (int Event, void *pData, void *pTag);
void DMNotify(int Event, void *pTsBuf, void *Tag);
bool IsPlaying(void) const;
bool IsEnabled(void) const;
void * GetHandle(void);
void * GetDmHandle(void);
#endif
};
#endif

1
azbox/pwrmngr.cpp Symbolic link
View File

@@ -0,0 +1 @@
../libspark/pwrmngr.cpp

1
azbox/pwrmngr.h Symbolic link
View File

@@ -0,0 +1 @@
../libspark/pwrmngr.h

1
azbox/record.cpp Symbolic link
View File

@@ -0,0 +1 @@
../libspark/record.cpp

1
azbox/record_lib.h Symbolic link
View File

@@ -0,0 +1 @@
../libspark/record_lib.h

622
azbox/video.cpp Normal file
View File

@@ -0,0 +1,622 @@
/*
* (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 "video_lib.h"
#define VIDEO_DEVICE "/dev/dvb/adapter0/video0"
#include "lt_debug.h"
#define lt_debug(args...) _lt_debug(TRIPLE_DEBUG_VIDEO, this, args)
#define lt_info(args...) _lt_info(TRIPLE_DEBUG_VIDEO, this, args)
#define lt_debug_c(args...) _lt_debug(TRIPLE_DEBUG_VIDEO, NULL, args)
#define lt_info_c(args...) _lt_info(TRIPLE_DEBUG_VIDEO, NULL, args)
#define fop(cmd, args...) ({ \
int _r; \
if (fd >= 0) { \
if ((_r = ::cmd(fd, args)) < 0) \
lt_info(#cmd"(fd, "#args")\n"); \
else \
lt_debug(#cmd"(fd, "#args")\n");\
} \
else { _r = fd; } \
_r; \
})
cVideo * videoDecoder = NULL;
int system_rev = 0;
static bool hdmi_enabled = true;
static bool stillpicture = false;
#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
static int proc_put(const char *path, const char *value, const int len)
{
int ret, ret2;
int pfd = open(path, O_WRONLY);
if (pfd < 0)
return pfd;
ret = write(pfd, value, len);
ret2 = close(pfd);
if (ret2 < 0)
return ret2;
return ret;
}
static int proc_get(const char *path, char *value, const int len)
{
int ret, ret2;
int pfd = open(path, O_RDONLY);
if (pfd < 0)
return pfd;
ret = read(pfd, value, len);
value[len-1] = '\0'; /* make sure string is terminated */
while (ret > 0 && isspace(value[ret-1]))
value[--ret] = '\0'; /* remove trailing whitespace */
ret2 = close(pfd);
if (ret2 < 0)
return ret2;
return ret;
}
static unsigned int proc_get_hex(const char *path)
{
unsigned int n, ret = 0;
char buf[16];
n = proc_get(path, buf, 16);
if (n > 0)
sscanf(buf, "%x", &ret);
return ret;
}
cVideo::cVideo(int, void *, void *)
{
lt_debug("%s\n", __FUNCTION__);
//croppingMode = VID_DISPMODE_NORM;
//outputformat = VID_OUTFMT_RGBC_SVIDEO;
scartvoltage = -1;
video_standby = 0;
fd = -1;
openDevice();
}
cVideo::~cVideo(void)
{
closeDevice();
}
void cVideo::openDevice(void)
{
int n = 0;
lt_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)) < 0)
{
if (errno == EBUSY)
{
/* sometimes we get busy quickly after close() */
usleep(50000);
if (++n < 10)
goto retry;
}
lt_info("%s cannot open %s: %m, retries %d\n", __func__, VIDEO_DEVICE, n);
}
else
fcntl(fd, F_SETFD, FD_CLOEXEC);
playstate = VIDEO_STOPPED;
}
void cVideo::closeDevice(void)
{
lt_debug("%s\n", __func__);
/* looks like sometimes close is unhappy about non-empty buffers */
Start();
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" };
static const char *m[] = { "panscan", "letterbox", "bestfit", "nonlinear", "(unset)" };
int n;
lt_debug("%s: a:%d m:%d %s\n", __func__, aspect, mode, m[(mode < 0||mode > 3) ? 4 : mode]);
if (aspect > 3 || aspect == 0)
lt_info("%s: invalid aspect: %d\n", __func__, aspect);
else if (aspect > 0) /* -1 == don't set */
{
lt_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)
lt_info("%s: proc_put /proc/stb/video/aspect (%m)\n", __func__);
}
if (mode == -1)
return 0;
lt_debug("%s: /proc/stb/video/policy -> %s\n", __func__, m[mode]);
n = proc_put("/proc/stb/video/policy", m[mode], strlen(m[mode]));
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)
{
lt_info("%s: VIDEO_GET_SIZE %m\n", __func__);
return -1;
}
lt_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!";
lt_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*/)
{
lt_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)
{
lt_debug("%s(%d)\n", __FUNCTION__, blank);
if (stillpicture)
{
lt_debug("%s: stillpicture == true\n", __func__);
return -1;
}
playstate = blank ? VIDEO_STOPPED : VIDEO_FREEZED;
return fop(ioctl, VIDEO_STOP, blank ? 1 : 0);
}
int cVideo::setBlank(int)
{
return Stop(1);
}
int cVideo::SetVideoSystem(int video_system, bool remember)
{
lt_debug("%s(%d, %d)\n", __func__, video_system, remember);
char current[32];
static const char *modes[] = {
"pal", // VIDEO_STD_NTSC
"pal", // VIDEO_STD_SECAM
"pal", // VIDEO_STD_PAL
"480p", // VIDEO_STD_480P
"576p50", // 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)
{
lt_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)
{
lt_info("%s: video_system %d (%s) already set, skipping\n", __func__, video_system, current);
return 0;
}
lt_info("%s: old: '%s' new: '%s'\n", __func__, current, modes[video_system]);
bool stopped = false;
if (playstate == VIDEO_PLAYING)
{
lt_info("%s: playstate == VIDEO_PLAYING, stopping video\n", __func__);
Stop();
stopped = true;
}
ret = proc_put("/proc/stb/video/videomode", modes[video_system],strlen(modes[video_system]));
if (stopped)
Start();
return ret;
}
int cVideo::getPlayState(void)
{
return playstate;
}
void cVideo::SetVideoMode(analog_mode_t mode)
{
lt_debug("%s(%d)\n", __func__, mode);
if (!(mode & ANALOG_SCART_MASK))
{
lt_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:
lt_info("%s unknown mode %d\n", __func__, mode);
m = "rgb";
break; /* default to rgb */
}
proc_put("/proc/stb/avs/0/colorformat", m, strlen(m));
}
void cVideo::ShowPicture(const char * fname)
{
lt_debug("%s(%s)\n", __func__, fname);
static const unsigned char pes_header[] = { 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x80, 0x00, 0x00 };
static const unsigned char seq_end[] = { 0x00, 0x00, 0x01, 0xB7 };
char destname[512];
char cmd[512];
char *p;
int mfd;
struct stat st, st2;
if (video_standby)
{
/* does not work and the driver does not seem to like it */
lt_info("%s: video_standby == true\n", __func__);
return;
}
strcpy(destname, "/var/cache");
if (stat(fname, &st2))
{
lt_info("%s: could not stat %s (%m)\n", __func__, fname);
return;
}
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);
}
mfd = open(destname, O_RDONLY);
if (mfd < 0)
{
lt_info("%s cannot open %s: %m", __func__, destname);
goto out;
}
fstat(mfd, &st);
closeDevice();
openDevice();
if (fd >= 0)
{
stillpicture = true;
if (ioctl(fd, VIDEO_SET_FORMAT, VIDEO_FORMAT_16_9) < 0)
lt_info("%s: VIDEO_SET_FORMAT failed (%m)\n", __func__);
bool seq_end_avail = false;
size_t pos=0;
unsigned char *iframe = (unsigned char *)malloc((st.st_size < 8192) ? 8192 : st.st_size);
if (! iframe)
{
lt_info("%s: malloc failed (%m)\n", __func__);
goto out;
}
read(mfd, iframe, st.st_size);
ioctl(fd, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY);
ioctl(fd, VIDEO_PLAY);
ioctl(fd, VIDEO_CONTINUE);
ioctl(fd, VIDEO_CLEAR_BUFFER);
while (pos <= (st.st_size-4) && !(seq_end_avail = (!iframe[pos] && !iframe[pos+1] && iframe[pos+2] == 1 && iframe[pos+3] == 0xB7)))
++pos;
if ((iframe[3] >> 4) != 0xE) // no pes header
write(fd, pes_header, sizeof(pes_header));
write(fd, iframe, st.st_size);
if (!seq_end_avail)
write(fd, seq_end, sizeof(seq_end));
memset(iframe, 0, 8192);
write(fd, iframe, 8192);
ioctl(fd, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX);
free(iframe);
}
out:
close(mfd);
return;
}
void cVideo::StopPicture()
{
lt_debug("%s\n", __func__);
stillpicture = false;
}
void cVideo::Standby(unsigned int bOn)
{
lt_debug("%s(%d)\n", __func__, bOn);
if (bOn)
{
closeDevice();
//hdmi_out(false);
}
else
{
/* only enable HDMI output when coming from standby, not on
* start. I have no idea why, but enabling it on startup leads
* to strange locking problems of the framebuffer driver :-( */
if (!hdmi_enabled)
{
//hdmi_out(true);
/* make sure the driver has time to settle.
* again - lame, but makes it work... */
//sleep(1);
}
openDevice();
}
video_standby = bOn;
}
int cVideo::getBlank(void)
{
lt_debug("%s\n", __FUNCTION__);
return 0;
}
/* 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)
{
lt_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") */
lt_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;
}
lt_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 29976:
return 3;
case 30:
return 4;
case 50:
return 5;
case 50940:
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;
lt_debug("%s: rate: %d, width: %d height: %d\n", __func__, rate, width, height);
}
void cVideo::SetSyncMode(AVSYNC_TYPE mode)
{
lt_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;
lt_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)
lt_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)
lt_info("%s: GET_PTS failed (%m)\n", __func__);
return pts;
}

194
azbox/video_lib.h Normal file
View File

@@ -0,0 +1,194 @@
#ifndef _VIDEO_TD_H
#define _VIDEO_TD_H
#include <linux/dvb/video.h>
typedef enum {
ANALOG_SD_RGB_CINCH = 0x00,
ANALOG_SD_YPRPB_CINCH,
ANALOG_HD_RGB_CINCH,
ANALOG_HD_YPRPB_CINCH,
ANALOG_SD_RGB_SCART = 0x10,
ANALOG_SD_YPRPB_SCART,
ANALOG_HD_RGB_SCART,
ANALOG_HD_YPRPB_SCART,
ANALOG_SCART_MASK = 0x10
} analog_mode_t;
typedef enum {
VIDEO_FORMAT_MPEG2 = 0,
VIDEO_FORMAT_MPEG4,
VIDEO_FORMAT_VC1,
VIDEO_FORMAT_JPEG,
VIDEO_FORMAT_GIF,
VIDEO_FORMAT_PNG
} VIDEO_FORMAT;
typedef enum {
VIDEO_SD = 0,
VIDEO_HD,
VIDEO_120x60i,
VIDEO_320x240i,
VIDEO_1440x800i,
VIDEO_360x288i
} VIDEO_DEFINITION;
typedef enum {
VIDEO_FRAME_RATE_23_976 = 0,
VIDEO_FRAME_RATE_24,
VIDEO_FRAME_RATE_25,
VIDEO_FRAME_RATE_29_97,
VIDEO_FRAME_RATE_30,
VIDEO_FRAME_RATE_50,
VIDEO_FRAME_RATE_59_94,
VIDEO_FRAME_RATE_60
} VIDEO_FRAME_RATE;
typedef enum {
DISPLAY_AR_1_1,
DISPLAY_AR_4_3,
DISPLAY_AR_14_9,
DISPLAY_AR_16_9,
DISPLAY_AR_20_9,
DISPLAY_AR_RAW,
} DISPLAY_AR;
typedef enum {
DISPLAY_AR_MODE_PANSCAN = 0,
DISPLAY_AR_MODE_LETTERBOX,
DISPLAY_AR_MODE_NONE,
DISPLAY_AR_MODE_PANSCAN2
} DISPLAY_AR_MODE;
typedef enum {
VIDEO_DB_DR_NEITHER = 0,
VIDEO_DB_ON,
VIDEO_DB_DR_BOTH
} VIDEO_DB_DR;
typedef enum {
VIDEO_PLAY_STILL = 0,
VIDEO_PLAY_CLIP,
VIDEO_PLAY_TRICK,
VIDEO_PLAY_MOTION,
VIDEO_PLAY_MOTION_NO_SYNC
} VIDEO_PLAY_MODE;
typedef enum {
VIDEO_STD_NTSC,
VIDEO_STD_SECAM,
VIDEO_STD_PAL,
VIDEO_STD_480P,
VIDEO_STD_576P,
VIDEO_STD_720P60,
VIDEO_STD_1080I60,
VIDEO_STD_720P50,
VIDEO_STD_1080I50,
VIDEO_STD_1080P30,
VIDEO_STD_1080P24,
VIDEO_STD_1080P25,
VIDEO_STD_AUTO,
VIDEO_STD_1080P50, /* SPARK only */
VIDEO_STD_MAX = VIDEO_STD_1080P50
} VIDEO_STD;
/* not used, for dummy functions */
typedef enum {
VIDEO_HDMI_CEC_MODE_OFF = 0,
VIDEO_HDMI_CEC_MODE_TUNER,
VIDEO_HDMI_CEC_MODE_RECORDER
} VIDEO_HDMI_CEC_MODE;
typedef enum
{
VIDEO_CONTROL_BRIGHTNESS = 0,
VIDEO_CONTROL_CONTRAST,
VIDEO_CONTROL_SATURATION,
VIDEO_CONTROL_HUE,
VIDEO_CONTROL_SHARPNESS,
VIDEO_CONTROL_MAX = VIDEO_CONTROL_SHARPNESS
} VIDEO_CONTROL;
class cVideo
{
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 *);
~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);
#define AVSYNC_TYPE int
void SetSyncMode(AVSYNC_TYPE mode);
bool SetCECMode(VIDEO_HDMI_CEC_MODE) { return true; };
void SetCECAutoView(bool) { return; };
void SetCECAutoStandby(bool) { return; };
void ShowPicture(const char * fname);
void StopPicture();
void Standby(unsigned int bOn);
void Pig(int x, int y, int w, int h, int osd_w = 1064, int osd_h = 600);
void SetControl(int, int) { return; };
void 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; };
};
#endif

View File

@@ -22,6 +22,7 @@ AC_OUTPUT([
Makefile Makefile
common/Makefile common/Makefile
libeplayer3/Makefile libeplayer3/Makefile
azbox/Makefile
libtriple/Makefile libtriple/Makefile
libspark/Makefile libspark/Makefile
tools/Makefile tools/Makefile

View File

@@ -3,6 +3,8 @@
#include "../libtriple/audio_td.h" #include "../libtriple/audio_td.h"
#elif HAVE_SPARK_HARDWARE #elif HAVE_SPARK_HARDWARE
#include "../libspark/audio_lib.h" #include "../libspark/audio_lib.h"
#elif HAVE_AZBOX_HARDWARE
#include "../azbox/audio_lib.h"
#else #else
#error neither HAVE_TRIPLEDRAGON nor HAVE_SPARK_HARDWARE defined #error neither HAVE_TRIPLEDRAGON nor HAVE_SPARK_HARDWARE defined
#endif #endif

View File

@@ -3,6 +3,8 @@
#include "../libtriple/cs_api.h" #include "../libtriple/cs_api.h"
#elif HAVE_SPARK_HARDWARE #elif HAVE_SPARK_HARDWARE
#include "../libspark/cs_api.h" #include "../libspark/cs_api.h"
#elif HAVE_AZBOX_HARDWARE
#include "../azbox/cs_api.h"
#else #else
#error neither HAVE_TRIPLEDRAGON nor HAVE_SPARK_HARDWARE defined #error neither HAVE_TRIPLEDRAGON nor HAVE_SPARK_HARDWARE defined
#endif #endif

View File

@@ -3,6 +3,8 @@
#include "../libtriple/dmx_td.h" #include "../libtriple/dmx_td.h"
#elif HAVE_SPARK_HARDWARE #elif HAVE_SPARK_HARDWARE
#include "../libspark/dmx_lib.h" #include "../libspark/dmx_lib.h"
#elif HAVE_AZBOX_HARDWARE
#include "../azbox/dmx_lib.h"
#else #else
#error neither HAVE_TRIPLEDRAGON nor HAVE_SPARK_HARDWARE defined #error neither HAVE_TRIPLEDRAGON nor HAVE_SPARK_HARDWARE defined
#endif #endif

View File

@@ -3,6 +3,8 @@
#include "../libtriple/playback_td.h" #include "../libtriple/playback_td.h"
#elif HAVE_SPARK_HARDWARE #elif HAVE_SPARK_HARDWARE
#include "../libspark/playback_libeplayer3.h" #include "../libspark/playback_libeplayer3.h"
#elif HAVE_AZBOX_HARDWARE
#include "../azbox/playback.h"
#else #else
#error neither HAVE_TRIPLEDRAGON nor HAVE_SPARK_HARDWARE defined #error neither HAVE_TRIPLEDRAGON nor HAVE_SPARK_HARDWARE defined
#endif #endif

View File

@@ -3,6 +3,8 @@
#include "../libtriple/pwrmngr.h" #include "../libtriple/pwrmngr.h"
#elif HAVE_SPARK_HARDWARE #elif HAVE_SPARK_HARDWARE
#include "../libspark/pwrmngr.h" #include "../libspark/pwrmngr.h"
#elif HAVE_AZBOX_HARDWARE
#include "../azbox/pwrmngr.h"
#else #else
#error neither HAVE_TRIPLEDRAGON nor HAVE_SPARK_HARDWARE defined #error neither HAVE_TRIPLEDRAGON nor HAVE_SPARK_HARDWARE defined
#endif #endif

View File

@@ -3,6 +3,8 @@
#include "../libtriple/record_td.h" #include "../libtriple/record_td.h"
#elif HAVE_SPARK_HARDWARE #elif HAVE_SPARK_HARDWARE
#include "../libspark/record_lib.h" #include "../libspark/record_lib.h"
#elif HAVE_AZBOX_HARDWARE
#include "../azbox/record_lib.h"
#else #else
#error neither HAVE_TRIPLEDRAGON nor HAVE_SPARK_HARDWARE defined #error neither HAVE_TRIPLEDRAGON nor HAVE_SPARK_HARDWARE defined
#endif #endif

View File

@@ -3,6 +3,8 @@
#include "../libtriple/video_td.h" #include "../libtriple/video_td.h"
#elif HAVE_SPARK_HARDWARE #elif HAVE_SPARK_HARDWARE
#include "../libspark/video_lib.h" #include "../libspark/video_lib.h"
#elif HAVE_AZBOX_HARDWARE
#include "../azbox/video_lib.h"
#else #else
#error neither HAVE_TRIPLEDRAGON nor HAVE_SPARK_HARDWARE defined #error neither HAVE_TRIPLEDRAGON nor HAVE_SPARK_HARDWARE defined
#endif #endif