38 Commits
0.4.6 ... 0.4.8

Author SHA1 Message Date
Johns
a7f0cf6d6f Version 0.4.8 released. 2012-02-16 09:59:40 +01:00
Johns
346953d209 Fix message, if no hq scaling is supported. 2012-02-16 09:58:13 +01:00
Johns
97af9c6de2 Fix bug: wrong start of video packet. 2012-02-15 22:19:50 +01:00
Johns
8dd95dab5e VDPAU: Enable inverse telecine configuration. 2012-02-14 22:29:17 +01:00
Johns
6775173e4f Fix bug: local id variable overwrites argument. 2012-02-14 21:51:13 +01:00
Johns
9170fcf485 Removed stupid gcc warnings. 2012-02-14 21:48:42 +01:00
Johns
919428cb80 Find AC3 (Dolby Digital) inside PES packet. 2012-02-14 21:18:24 +01:00
Johns
4331692ee5 Fix bug: audio increments invalid audio PTS. 2012-02-14 16:03:08 +01:00
Johns
5aa826bdb0 Fix bug: dvd plugin not working. 2012-02-14 15:12:48 +01:00
Johns
6736db082e Fix bug: used frame-> instead of video_ctx->. 2012-02-14 14:46:49 +01:00
Johns
807b4df381 Release Version 0.4.7. 2012-02-13 23:21:11 +01:00
56edfd4f54 Fix bug: unscaled jpeg includes PNG header. 2012-02-13 20:15:25 +01:00
Johns
0a1a258d2a Update dependencies and install README. 2012-02-13 14:58:26 +01:00
Johns
09a0880d07 Update readme for new featurs. 2012-02-13 14:25:38 +01:00
Johns
a98a4adc7e Studio levels could be configured in setup menu. 2012-02-13 14:13:24 +01:00
Johns
f872f54e2a Window defaults to fullscreen without geometry. 2012-02-13 14:00:53 +01:00
33c638d538 Jpeg screengrab use VDR RgbToJpeg function. 2012-02-12 20:30:50 +01:00
Johns
0a2a221fa9 Add play/pause audio support. 2012-02-12 20:14:43 +01:00
Johns
24a065e5de Fix bug: audible glitch toggling AC-3 pass-through 2012-02-12 17:50:10 +01:00
Johns
6df970ca9e Fix bug: mpeg stills not displayed. 2012-02-12 16:57:32 +01:00
Johns
616cd9e133 Forgot to reenable FindAudioSync. 2012-02-11 18:29:20 +01:00
Johns
a91533f6d1 Detect audio stream type only after stream switch. 2012-02-11 18:22:48 +01:00
Johns
baa4500a2c Detect more h264 streams with leading zeros. 2012-02-11 17:18:44 +01:00
Johns
f28a737a9a VDPAU: support for studio levels added. 2012-02-10 15:47:52 +01:00
Johns
19cec561ba Fix bug #876: Keypad not working. 2012-02-10 10:43:31 +01:00
Johns
d8f63adaad Software deinterlacer (config/skip chroma deint):
Add support for skip chroma deinterlace to software deinterlacer.
Type of software deinterlacer now configurable from setup menu.
2012-02-09 21:22:42 +01:00
Johns
8c16466d31 Set mixer channel through command line option 2012-02-09 16:01:36 +01:00
Johns
ced54a5cf1 Fix bug: LFE moved to wrong position. 2012-02-09 00:46:02 +01:00
Johns
08246b5ac3 Guard suspend/resume against multiple calls. 2012-02-08 23:26:49 +01:00
Johns
c3a1de8c7b jpeg_mem_dest only supported by jpeg 8.0. 2012-02-08 22:32:47 +01:00
Johns
918170d00b Add support for AAC LATM audio streams. 2012-02-08 15:19:18 +01:00
Johns
bc50f37c4d Spatial deinterlacer for VA-API. 2012-02-07 18:18:13 +01:00
Johns
09cf1f5c85 Fix bug: alsa+ffmpeg use different channel layout. 2012-02-07 17:08:59 +01:00
Johns
947f6b312e Support more LPCM sample rates and channels. 2012-02-06 23:54:22 +01:00
Johns
99728258f1 Quick&dirty support for mpeg LPCM streams. 2012-02-06 22:58:42 +01:00
Johns
c972f8c4dd Workaround for text2skin undrawn OSD areas. 2012-02-06 20:54:20 +01:00
Johns
7d38dff5bf Detect dvb LPCM stream and ignore it. 2012-02-05 14:17:46 +01:00
Johns
8db8b68edd Makes Workarounds command line configurable. 2012-02-04 16:38:10 +01:00
12 changed files with 1455 additions and 360 deletions

View File

@@ -1,3 +1,56 @@
User johns
Date: Thu Feb 16 09:59:14 CET 2012
Release Version 0.4.8
Fix bug: wrong start of video packet.
VDPAU: Enables inverse telecine configuration.
Find AC3 (Dolby Digital) inside PES packet.
Fix bug: audio increments invalid audio PTS.
Fix bug: dvd plugin not working.
Fix bug: used frame-> instead of video_ctx-> for old libav/ffmpeg.
User johns
Date: Mon Feb 13 23:20:26 CET 2012
Release Version 0.4.7
User FireFly
Date: Mon Feb 13 20:14:11 CET 2012
Fix bug: unscaled jpeg includes PNG header.
User johns
Date: Mon Feb 13 14:58:26 CET 2012
VDPAU: Studio levels could be configured in the setup menu.
Window size defaults to fullscreen, if no geometry is given.
User m.Rcu
Date: Sun Feb 12 20:28:22 CET 2012
Jpeg screengrab use VDR RgbToJpeg function.
User johns
Date: Sun Feb 12 20:14:43 CET 2012
Add play/pause audio support.
Fix bug: audible glitch when switching AC-3 pass-through <-> none.
Fix bug: mpeg stills not displayed.
Detect audio stream type only after stream switch.
Detect more h264 streams with leading zeros.
VDPAU: support for studio levels added.
Add support for skip chroma deinterlace to software deinterlacer.
Type of software deinterlacer now configurable from setup menu.
Mixer channel could be set through command line option.
Fix bug: LFE moved to wrong position.
Guard suspend/resume against multiple calls.
Add support for AAC LATM audio streams.
Fix bug: alsa and ffmpeg use different channel layout.
Support more LPCM sample rates and number of channels.
Quick&dirty support for mpeg LPCM streams.
Workaround for text2skin undrawn OSD areas.
Detect dvb LPCM stream and ignore it.
User johns
Date: Thu Feb 2 23:29:35 CET 2012

View File

@@ -24,15 +24,15 @@ CONFIG += -DAV_INFO
CONFIG += $(shell pkg-config --exists vdpau && echo "-DUSE_VDPAU")
CONFIG += $(shell pkg-config --exists libva && echo "-DUSE_VAAPI")
CONFIG += $(shell pkg-config --exists alsa && echo "-DUSE_ALSA")
CONFIG += $(shell ls /usr/lib/libjpeg* >/dev/null 2>&1 && echo "-DUSE_JPEG")
CONFIG += -DUSE_OSS
### The C++ compiler and options:
CC ?= gcc
CXX ?= g++
CFLAGS ?= -g -O2 -W -Wall -Wextra -Winit-self \
-Wdeclaration-after-statement
CC ?= gcc
CXX ?= g++
CFLAGS ?= -g -O2 -W -Wall -Wextra -Winit-self \
-Wdeclaration-after-statement \
-ftree-vectorize -msse3 -flax-vector-conversions
CXXFLAGS ?= -g -O2 -W -Wall -Wextra -Woverloaded-virtual
### The directory environment:
@@ -71,15 +71,15 @@ _CFLAGS = $(DEFINES) $(INCLUDES) \
xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\
`pkg-config --cflags gl glu` \
$(if $(findstring USE_VDPAU,$(CONFIG)), \
`pkg-config --cflags vdpau`) \
`pkg-config --cflags vdpau`) \
$(if $(findstring USE_VAAPI,$(CONFIG)), \
`pkg-config --cflags libva-x11 libva-glx libva`) \
`pkg-config --cflags libva-x11 libva-glx libva`) \
$(if $(findstring USE_ALSA,$(CONFIG)), \
`pkg-config --cflags alsa`)
`pkg-config --cflags alsa`)
#override _CFLAGS += -Werror
override CXXFLAGS += $(_CFLAGS)
override CFLAGS += $(_CFLAGS)
override CFLAGS += $(_CFLAGS)
LIBS += -lrt \
$(shell pkg-config --libs libavcodec libavformat) \
@@ -87,13 +87,11 @@ LIBS += -lrt \
xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\
`pkg-config --libs gl glu` \
$(if $(findstring USE_VDPAU,$(CONFIG)), \
`pkg-config --libs vdpau`) \
`pkg-config --libs vdpau`) \
$(if $(findstring USE_VAAPI,$(CONFIG)), \
`pkg-config --libs libva-x11 libva-glx libva`) \
`pkg-config --libs libva-x11 libva-glx libva`) \
$(if $(findstring USE_ALSA,$(CONFIG)), \
`pkg-config --libs alsa`) \
$(if $(findstring USE_JPEG,$(CONFIG)), \
-ljpeg)
`pkg-config --libs alsa`)
### The object files (add further files here):
@@ -122,11 +120,11 @@ $(OBJS): Makefile
### Internationalization (I18N):
PODIR = po
PODIR = po
LOCALEDIR = $(VDRDIR)/locale
I18Npo = $(wildcard $(PODIR)/*.po)
I18Npo = $(wildcard $(PODIR)/*.po)
I18Nmsgs = $(addprefix $(LOCALEDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file))))))
I18Npot = $(PODIR)/$(PLUGIN).pot
I18Npot = $(PODIR)/$(PLUGIN).pot
%.mo: %.po
msgfmt -c -o $@ $<

View File

@@ -76,6 +76,13 @@ Setup: environment
DISPLAY=:0.0
x11 display name
NO_HW=1
if set don't use the hardware decoders
NO_MPEG_HW=1
if set don't use the hardware decoder for mpeg1/2
STUDIO_LEVELS=1
if set use studio levels with vdpau (deprecated use setup)
only if alsa is configured
ALSA_DEVICE=default
alsa PCM device name
@@ -85,6 +92,7 @@ Setup: environment
alsa control device name
ALSA_MIXER_CHANNEL=PCM
alsa control channel name
only if oss is configured
OSS_AUDIODEV=/dev/dsp
oss dsp device name
@@ -105,7 +113,7 @@ Setup: /etc/vdr/setup.conf
softhddevice.HideMainMenuEntry = 0
0 = show softhddevice main menu entry, 1 = hide entry
<res> of the next parameters is 567i, 720p, 1080i_fake or 1080i.
<res> of the next parameters is 576i, 720p, 1080i_fake or 1080i.
1080i_fake is 1280x1080 or 1440x1080
1080i is "real" 1920x1080
@@ -119,6 +127,9 @@ Setup: /etc/vdr/setup.conf
softhddevice.<res>.SkipChromaDeinterlace = 0
0 = disabled, 1 = enabled (for slower cards, poor qualit<69>t)
softhddevice.<res>.InverseTelecine = 0
0 = disabled, 1 = enabled
softhddevice.<res>.Denoise = 0
0 .. 1000 noise reduction level (0 off, 1000 max)
@@ -149,6 +160,10 @@ Setup: /etc/vdr/setup.conf
softhddevice.SkipLines = 0
skip 'n' lines at top and bottom of the video picture.
softhddevice.StudioLevels = 0
0 use PC levels (0-255) with vdpau.
1 use studio levels (16-235) with vdpau.
softhddevice.Suspend.Close = 0
1 suspend closes x11 window, connection and audio device.
(use svdrpsend plug softhddevice RESU to resume, if you have no lirc)
@@ -156,6 +171,11 @@ Setup: /etc/vdr/setup.conf
softhddevice.Suspend.X11 = 0
1 suspend stops X11 server (not working yet)
VideoDisplayFormat = ?
0 pan and scan
1 letter box
2 center cut-out
Setup: /etc/vdr/remote.conf
------

18
Todo
View File

@@ -21,10 +21,11 @@ $Id: $
missing:
software deinterlace (yadif, ...)
software decoder with software deinterlace
ITU BT601, ITU BT709 (HD), RGB studio levels (16-235)?
suspend output / energie saver: stop and restart X11
suspend plugin didn't restore full-screen (is this wanted?)
Option deinterlace off / deinterlace force!
ColorSpace aren't configurable with the gui.
Inverse telecine isn't configurable with the gui.
crash:
AudioPlayHandlerThread -> pthread_cond_wait
@@ -34,11 +35,10 @@ video:
subtitle could be asyncron
reduce warnings after channel switch
grab image with hardware and better scaling support
suspendoutput didn't show logo or black pictures
(must detect video format to show image)
hard channel switch
skip lines not configurable from setup menu.
OSD can only be shown after some stream could be shown
yaepghd changed position is lost on channel switch
pause (live tv) has sometime problems with SAT1 HD Pro7 HD
vdpau:
software decoder path not working
@@ -80,7 +80,9 @@ audio:
Combine alsa+oss ringbuffer code.
Make alsa thread/polled and oss thread/polled output module runtime
selectable.
software volume support
software volume support (could be done with asound.conf)
Mute should do a real mute and not only set volume to zero.
Starting suspended and muted, didn't register the mute.
audio/alsa:
better downmix of >2 channels on 2 channel hardware
@@ -95,8 +97,6 @@ audio/oss:
HDMI/SPDIF Passthrough:
only AC-3 written
Channels are wrong setup, if changing setting during operation.
support oss pass-through
playback of recording
pause is not reset, when replay exit
@@ -111,8 +111,6 @@ setup:
Can a notice be added to the setup menu?
unsorted:
Menu -> Setup -> Plugins -> skingenigmang -> General
-> Try 8bpp single area: no, has missing parts.
stoping vdr while plugin is suspended opens and closes a window.
future features (not planed for 1.0 - 1.5)
@@ -126,4 +124,4 @@ future features (not planed for 1.0 - 1.5)
pip support
save and use auto-crop with channel zapping
upmix stereo to AC-3
upmix stereo to AC-3 (supported by alsa plugin)

156
audio.c
View File

@@ -113,6 +113,8 @@ typedef struct _audio_module_
uint64_t(*GetDelay) (void); ///< get current audio delay
void (*SetVolume) (int); ///< set output volume
int (*Setup) (int *, int *, int); ///< setup channels, samplerate
void (*Play) (void); ///< play
void (*Pause) (void); ///< pause
void (*Init) (void); ///< initialize audio output module
void (*Exit) (void); ///< cleanup audio output module
} AudioModule;
@@ -123,6 +125,8 @@ static const AudioModule NoopModule; ///< forward definition of noop module
// Variables
//----------------------------------------------------------------------------
char AudioAlsaDriverBroken; ///< disable broken driver message
static const char *AudioModuleName; ///< which audio module to use
/// Selected audio module.
@@ -132,7 +136,7 @@ static const char *AudioAC3Device; ///< alsa/OSS AC3 device name
static const char *AudioMixerDevice; ///< alsa/OSS mixer device name
static const char *AudioMixerChannel; ///< alsa/OSS mixer channel name
static volatile char AudioRunning; ///< thread running / stopped
static int AudioPaused; ///< audio paused
static volatile char AudioPaused; ///< audio paused
static unsigned AudioSampleRate; ///< audio sample rate in hz
static unsigned AudioChannels; ///< number of audio channels
static const int AudioBytesProSample = 2; ///< number of bytes per sample
@@ -285,10 +289,12 @@ static int AlsaAddToRingbuffer(const void *samples, int count)
// too many bytes are lost
// FIXME: should skip more, longer skip, but less often?
}
// Update audio clock
AudioPTS +=
((int64_t) count * 90000) / (AudioSampleRate * AudioChannels *
AudioBytesProSample);
// Update audio clock (stupid gcc developers thinks INT64_C is unsigned)
if (AudioPTS != (int64_t) INT64_C(0x8000000000000000)) {
AudioPTS +=
((int64_t) count * 90000) / (AudioSampleRate * AudioChannels *
AudioBytesProSample);
}
if (!AudioRunning) {
if (AlsaStartThreshold < RingBufferUsedBytes(AlsaRingBuffer)) {
@@ -334,7 +340,9 @@ static int AlsaPlayRingbuffer(void)
if (first) {
// happens with broken alsa drivers
if (AudioThread) {
Error(_("audio/alsa: broken driver %d\n"), avail);
if (!AudioAlsaDriverBroken) {
Error(_("audio/alsa: broken driver %d\n"), avail);
}
usleep(5 * 1000);
}
}
@@ -563,7 +571,6 @@ static void AlsaEnqueue(const void *samples, int count)
state = snd_pcm_state(AlsaPCMHandle);
Debug(3, "audio/alsa: state %s\n", snd_pcm_state_name(state));
Debug(3, "audio/alsa: unpaused\n");
AudioPaused = 0;
}
}
// Update audio clock
@@ -622,6 +629,9 @@ static void AlsaThread(void)
AlsaFlushBuffer = 0;
break;
}
if (AudioPaused) {
break;
}
// wait for space in kernel buffers
if ((err = snd_pcm_wait(AlsaPCMHandle, 100)) < 0) {
Error(_("audio/alsa: wait underrun error?\n"));
@@ -633,7 +643,7 @@ static void AlsaThread(void)
usleep(100 * 1000);
continue;
}
if (AlsaFlushBuffer) {
if (AlsaFlushBuffer || AudioPaused) {
continue;
}
if ((err = AlsaPlayRingbuffer())) { // empty / error
@@ -818,7 +828,7 @@ static void AlsaInitMixer(void)
const char *name;
name = snd_mixer_selem_get_name(alsa_mixer_elem);
if (strcasecmp(name, alsa_mixer_elem_name) == 0) {
if (!strcasecmp(name, alsa_mixer_elem_name)) {
snd_mixer_selem_get_playback_volume_range(alsa_mixer_elem,
&alsa_mixer_elem_min, &alsa_mixer_elem_max);
AlsaRatio =
@@ -1107,6 +1117,47 @@ static int AlsaSetup(int *freq, int *channels, int use_ac3)
return ret;
}
/**
** Play audio.
*/
void AlsaPlay(void)
{
int err;
if (AlsaCanPause) {
if ((err = snd_pcm_pause(AlsaPCMHandle, 0))) {
Error(_("audio/alsa: snd_pcm_pause(): %s\n"), snd_strerror(err));
}
} else {
if ((err = snd_pcm_prepare(AlsaPCMHandle)) < 0) {
Error(_("audio/alsa: snd_pcm_prepare(): %s\n"), snd_strerror(err));
}
}
#ifdef DEBUG
if (snd_pcm_state(AlsaPCMHandle) == SND_PCM_STATE_PAUSED) {
Error(_("audio/alsa: still paused\n"));
}
#endif
}
/**
** Pause audio.
*/
void AlsaPause(void)
{
int err;
if (AlsaCanPause) {
if ((err = snd_pcm_pause(AlsaPCMHandle, 1))) {
Error(_("snd_pcm_pause(): %s\n"), snd_strerror(err));
}
} else {
if ((err = snd_pcm_drop(AlsaPCMHandle)) < 0) {
Error(_("snd_pcm_drop(): %s\n"), snd_strerror(err));
}
}
}
/**
** Empty log callback
*/
@@ -1175,6 +1226,8 @@ static const AudioModule AlsaModule = {
.GetDelay = AlsaGetDelay,
.SetVolume = AlsaSetVolume,
.Setup = AlsaSetup,
.Play = AlsaPlay,
.Pause = AlsaPause,
.Init = AlsaInit,
.Exit = AlsaExit,
};
@@ -1223,10 +1276,12 @@ static int OssAddToRingbuffer(const void *samples, int count)
// too many bytes are lost
// FIXME: should skip more, longer skip, but less often?
}
// Update audio clock
AudioPTS +=
((int64_t) count * 90000) / (AudioSampleRate * AudioChannels *
AudioBytesProSample);
// Update audio clock (stupid gcc developers thinks INT64_C is unsigned)
if (AudioPTS != (int64_t) INT64_C(0x8000000000000000)) {
AudioPTS +=
((int64_t) count * 90000) / (AudioSampleRate * AudioChannels *
AudioBytesProSample);
}
if (!AudioRunning) {
if (OssStartThreshold < RingBufferUsedBytes(OssRingBuffer)) {
@@ -1384,6 +1439,9 @@ static void OssThread(void)
OssFlushBuffer = 0;
break;
}
if (AudioPaused) {
break;
}
fds[0].fd = OssPcmFildes;
fds[0].events = POLLOUT | POLLERR;
@@ -1395,7 +1453,7 @@ static void OssThread(void)
continue;
}
if (OssFlushBuffer) {
if (OssFlushBuffer || AudioPaused) {
continue;
}
@@ -1736,6 +1794,20 @@ static int OssSetup(int *freq, int *channels, int use_ac3)
return ret;
}
/**
** Play audio.
*/
void OssPlay(void)
{
}
/**
** Pause audio.
*/
void OssPause(void)
{
}
/**
** Initialize OSS audio output module.
*/
@@ -1781,6 +1853,8 @@ static const AudioModule OssModule = {
.GetDelay = OssGetDelay,
.SetVolume = OssSetVolume,
.Setup = OssSetup,
.Play = OssPlay,
.Pause = OssPause,
.Init = OssInit,
.Exit = OssExit,
};
@@ -1864,6 +1938,8 @@ static const AudioModule NoopModule = {
.GetDelay = NoopGetDelay,
.SetVolume = NoopSetVolume,
.Setup = NoopSetup,
.Play = NoopVoid,
.Pause = NoopVoid,
.Init = NoopVoid,
.Exit = NoopVoid,
};
@@ -2049,7 +2125,8 @@ void AudioSetClock(int64_t pts)
*/
int64_t AudioGetClock(void)
{
if ((uint64_t) AudioPTS != INT64_C(0x8000000000000000)) {
// (cast) needed for the evil gcc
if (AudioPTS != (int64_t) INT64_C(0x8000000000000000)) {
int64_t delay;
if ((delay = AudioGetDelay())) {
@@ -2066,13 +2143,7 @@ int64_t AudioGetClock(void)
*/
void AudioSetVolume(int volume)
{
#ifdef USE_ALSA
AlsaSetVolume(volume);
#endif
#ifdef USE_OSS
OssSetVolume(volume);
#endif
(void)volume;
return AudioUsedModule->SetVolume(volume);
}
/**
@@ -2106,6 +2177,32 @@ int AudioSetup(int *freq, int *channels, int use_ac3)
return AudioUsedModule->Setup(freq, channels, use_ac3);
}
/**
** Play audio.
*/
void AudioPlay(void)
{
if (!AudioPaused) {
Warning("audio: not paused, check the code\n");
return;
}
Debug(3, "audio: resumed\n");
AudioPaused = 0;
}
/**
** Pause audio.
*/
void AudioPause(void)
{
if (AudioPaused) {
Warning("audio: already paused, check the code\n");
return;
}
Debug(3, "audio: paused\n");
AudioPaused = 1;
}
/**
** Set pcm audio device.
**
@@ -2146,6 +2243,18 @@ void AudioSetDeviceAC3(const char *device)
AudioAC3Device = device;
}
/**
** Set pcm audio mixer channel.
**
** @param channel name of the mixer channel (fe. PCM or Master)
**
** @note this is currently used to select alsa/OSS output module.
*/
void AudioSetChannel(const char *channel)
{
AudioMixerChannel = channel;
}
/**
** Initialize audio output module.
**
@@ -2197,8 +2306,7 @@ void AudioInit(void)
AudioInitThread();
}
#endif
AudioPaused = 1;
AudioPaused = 0;
}
/**

13
audio.h
View File

@@ -39,12 +39,19 @@ extern int64_t AudioGetClock(); ///< get current audio clock
extern void AudioSetVolume(int); ///< set volume
extern int AudioSetup(int *, int *, int); ///< setup audio output
//extern void AudioPlay(void); ///< play audio
//extern void AudioPause(void); ///< pause audio
extern void AudioPlay(void); ///< play audio
extern void AudioPause(void); ///< pause audio
extern void AudioSetDevice(const char *); ///< set PCM audio device
extern void AudioSetDeviceAC3(const char *); ///< set Passthrough device
extern void AudioSetDeviceAC3(const char *); ///< set pass-through device
extern void AudioSetChannel(const char *); ///< set mixer channel
extern void AudioInit(void); ///< setup audio module
extern void AudioExit(void); ///< cleanup and exit audio module
//----------------------------------------------------------------------------
// Variables
//----------------------------------------------------------------------------
extern char AudioAlsaDriverBroken; ///< disable broken driver message
/// @}

80
codec.c
View File

@@ -605,6 +605,7 @@ struct _audio_decoder_
/// audio parser to support insane dvb streaks
AVCodecParserContext *AudioParser;
int PassthroughAC3; ///< current ac-3 pass-through
int SampleRate; ///< current stream sample rate
int Channels; ///< current stream channels
@@ -621,6 +622,9 @@ static char CodecPassthroughAC3; ///< pass ac3 through
//static char CodecPassthroughDTS; ///< pass dts through (unsupported)
//static char CodecPassthroughMPA; ///< pass mpa through (unsupported)
#else
static const int CodecPassthroughAC3 = 0;
#endif
/**
@@ -735,10 +739,65 @@ void CodecSetAudioPassthrough(int mask)
#ifdef USE_PASSTHROUGH
CodecPassthroughAC3 = mask & 1 ? 1 : 0;
#endif
// FIXME: must update audio decoder (nr. of channels wrong)
(void)mask;
}
/**
** Reorder audio frame.
**
** ffmpeg L R C Ls Rs -> alsa L R Ls Rs C
** ffmpeg L R C LFE Ls Rs -> alsa L R Ls Rs C LFE
** ffmpeg L R C LFE Ls Rs Rl Rr -> alsa L R Ls Rs C LFE Rl Rr
*/
static void CodecReorderAudioFrame(int16_t * buf, int size, int channels)
{
int i;
int c;
int ls;
int rs;
int lfe;
switch (channels) {
case 5:
size /= 2;
for (i = 0; i < size; i += 5) {
c = buf[i + 2];
ls = buf[i + 3];
rs = buf[i + 4];
buf[i + 2] = ls;
buf[i + 3] = rs;
buf[i + 4] = c;
}
break;
case 6:
size /= 2;
for (i = 0; i < size; i += 6) {
c = buf[i + 2];
lfe = buf[i + 3];
ls = buf[i + 4];
rs = buf[i + 5];
buf[i + 2] = ls;
buf[i + 3] = rs;
buf[i + 4] = c;
buf[i + 5] = lfe;
}
break;
case 8:
size /= 2;
for (i = 0; i < size; i += 8) {
c = buf[i + 2];
lfe = buf[i + 3];
ls = buf[i + 4];
rs = buf[i + 5];
buf[i + 2] = ls;
buf[i + 3] = rs;
buf[i + 4] = c;
buf[i + 5] = lfe;
}
break;
}
}
#ifdef USE_AVPARSER
/**
@@ -796,6 +855,10 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
dpkt->dts = audio_decoder->AudioParser->dts;
buf_sz = sizeof(buf);
l = avcodec_decode_audio3(audio_ctx, buf, &buf_sz, dpkt);
if (l == AVERROR(EAGAIN)) {
index += n; // this is needed for aac latm
continue;
}
if (l < 0) { // no audio frame could be decompressed
Error(_("codec: error audio data at %d\n"), index);
break;
@@ -812,11 +875,15 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
AudioSetClock(dpkt->pts);
}
// FIXME: must first play remainings bytes, than change and play new.
if (audio_decoder->SampleRate != audio_ctx->sample_rate
if (audio_decoder->PassthroughAC3 != CodecPassthroughAC3
|| audio_decoder->SampleRate != audio_ctx->sample_rate
|| audio_decoder->Channels != audio_ctx->channels) {
int err;
int isAC3;
audio_decoder->PassthroughAC3 = CodecPassthroughAC3;
// FIXME: use swr_convert from swresample (only in ffmpeg!)
// FIXME: tell ac3 decoder to use downmix
if (audio_decoder->ReSample) {
audio_resample_close(audio_decoder->ReSample);
audio_decoder->ReSample = NULL;
@@ -825,14 +892,11 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
audio_decoder->SampleRate = audio_ctx->sample_rate;
audio_decoder->HwSampleRate = audio_ctx->sample_rate;
audio_decoder->Channels = audio_ctx->channels;
#ifdef USE_PASSTHROUGH
// SPDIF/HDMI passthrough
if (CodecPassthroughAC3 && audio_ctx->codec_id == CODEC_ID_AC3) {
audio_decoder->HwChannels = 2;
isAC3 = 1;
} else
#endif
{
} else {
audio_decoder->HwChannels = audio_ctx->channels;
isAC3 = 0;
}
@@ -893,6 +957,8 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
audio_decoder->HwChannels *
av_get_bytes_per_sample(audio_ctx->sample_fmt);
Debug(4, "codec/audio: %d -> %d\n", buf_sz, outlen);
CodecReorderAudioFrame(outbuf, outlen,
audio_decoder->HwChannels);
AudioEnqueue(outbuf, outlen);
}
} else {
@@ -971,6 +1037,8 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
// True HD?
#endif
#endif
CodecReorderAudioFrame(buf, buf_sz,
audio_decoder->HwChannels);
AudioEnqueue(buf, buf_sz);
}
}

View File

@@ -39,9 +39,6 @@
#define __USE_GNU
#endif
#include <pthread.h>
#ifdef USE_JPEG
#include <jpeglib.h>
#endif
#include "misc.h"
#include "softhddev.h"
@@ -66,7 +63,7 @@ static char ConfigStartX11Server; ///< flag start the x11 server
static pthread_mutex_t SuspendLockMutex; ///< suspend lock mutex
static volatile char VideoFreezed; ///< video freezed
static volatile char StreamFreezed; ///< stream freezed
//////////////////////////////////////////////////////////////////////////////
// Audio
@@ -74,8 +71,10 @@ static volatile char VideoFreezed; ///< video freezed
static volatile char NewAudioStream; ///< new audio stream
static volatile char SkipAudio; ///< skip audio stream
static char AudioRawAc3; ///< flag raw ac3 stream
static AudioDecoder *MyAudioDecoder; ///< audio decoder
static enum CodecID AudioCodecID; ///< current codec id
static int AudioChannelID; ///< current audio channel id
/**
** mpeg bitrate table.
@@ -181,12 +180,67 @@ static int FindAudioSync(const AVPacket * avpkt)
"audio: mpeg%s layer%d bitrate=%d samplerate=%d %d bytes\n",
mpeg25 ? "2.5" : mpeg2 ? "2" : "1", layer, bit_rate,
sample_rate, frame_size);
if (i + frame_size < avpkt->size - 4) {
if (data[i + frame_size] == 0xFF
&& (data[i + frame_size + 1] & 0xFC) == 0xFC) {
Debug(3, "audio: mpeg1/2 found at %d\n", i);
return i;
}
// check if after this frame a new mpeg frame starts
if (i + frame_size < avpkt->size - 3
&& data[i + frame_size] == 0xFF
&& (data[i + frame_size + 1] & 0xFC) == 0xFC) {
Debug(3, "audio: mpeg1/2 found at %d\n", i);
return i;
}
// no valid frame size or no continuation, try next
}
i++;
}
return -1;
}
/**
** Possible AC3 frame sizes.
**
** from ATSC A/52 table 5.18 frame size code table.
*/
const uint16_t Ac3FrameSizeTable[38][3] = {
{64, 69, 96}, {64, 70, 96}, {80, 87, 120}, {80, 88, 120},
{96, 104, 144}, {96, 105, 144}, {112, 121, 168}, {112, 122, 168},
{128, 139, 192}, {128, 140, 192}, {160, 174, 240}, {160, 175, 240},
{192, 208, 288}, {192, 209, 288}, {224, 243, 336}, {224, 244, 336},
{256, 278, 384}, {256, 279, 384}, {320, 348, 480}, {320, 349, 480},
{384, 417, 576}, {384, 418, 576}, {448, 487, 672}, {448, 488, 672},
{512, 557, 768}, {512, 558, 768}, {640, 696, 960}, {640, 697, 960},
{768, 835, 1152}, {768, 836, 1152}, {896, 975, 1344}, {896, 976, 1344},
{1024, 1114, 1536}, {1024, 1115, 1536}, {1152, 1253, 1728},
{1152, 1254, 1728}, {1280, 1393, 1920}, {1280, 1394, 1920},
};
/**
** Find dolby sync in audio packet.
**
** @param avpkt audio packet
*/
static int FindDolbySync(const AVPacket * avpkt)
{
int i;
const uint8_t *data;
i = 0;
data = avpkt->data;
while (i < avpkt->size - 5) {
if (data[i] == 0x0B && data[i + 1] == 0x77) {
int fscod;
int frmsizcod;
int frame_size;
// crc1 crc1 fscod|frmsizcod
fscod = data[i + 4] >> 6;
frmsizcod = data[i + 4] & 0x3F;
frame_size = Ac3FrameSizeTable[frmsizcod][fscod] * 2;
// check if after this frame a new ac-3 frame starts
if (i + frame_size < avpkt->size - 5
&& data[i + frame_size] == 0x0B
&& data[i + frame_size + 1] == 0x77) {
Debug(3, "audio: ac-3 found at %d\n", i);
return i;
}
// no valid frame size or no continuation, try next
}
@@ -202,8 +256,7 @@ static int FindAudioSync(const AVPacket * avpkt)
** @param size size of PES packet
** @param id PES packet type
*/
int PlayAudio(const uint8_t * data, int size,
__attribute__ ((unused)) uint8_t id)
int PlayAudio(const uint8_t * data, int size, uint8_t id)
{
int n;
int osize;
@@ -211,7 +264,7 @@ int PlayAudio(const uint8_t * data, int size,
// channel switch: SetAudioChannelDevice: SetDigitalAudioDevice:
if (VideoFreezed) { // video freezed
if (StreamFreezed) { // stream freezed
return 0;
}
if (SkipAudio || !MyAudioDecoder) { // skip audio
@@ -261,64 +314,169 @@ int PlayAudio(const uint8_t * data, int size,
return osize;
}
// Detect audio code
// MPEG-PS mp2 MPEG1, MPEG2, AC3
// MPEG-PS mp2 MPEG1, MPEG2, AC3, LPCM, AAC LATM
// Syncword - 0x0B77
if (data[0] == 0x0B && data[1] == 0x77) {
if (AudioCodecID != CODEC_ID_AC3) {
Debug(3, "[softhddev]%s: AC-3 %d\n", __FUNCTION__, id);
CodecAudioClose(MyAudioDecoder);
CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_AC3);
AudioCodecID = CODEC_ID_AC3;
}
// Syncword - 0xFFFC - 0xFFFF
} else if (data[0] == 0xFF && (data[1] & 0xFC) == 0xFC) {
if (AudioCodecID != CODEC_ID_MP2) {
Debug(3, "[softhddev]%s: MP2 %d\n", __FUNCTION__, id);
CodecAudioClose(MyAudioDecoder);
CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_MP2);
AudioCodecID = CODEC_ID_MP2;
}
} else {
// no start package
// FIXME: Nick/Viva sends this shit, need to find sync in packet
// FIXME: otherwise it takes too long until sound appears
if (AudioCodecID == CODEC_ID_NONE) {
Debug(3, "[softhddev]%s: ??? %d\n", __FUNCTION__, id);
avpkt->data = (void *)data;
avpkt->size = size;
n = FindAudioSync(avpkt);
if (n < 0) {
return osize;
// only if unknown or new channel id
if (AudioCodecID == CODEC_ID_NONE || AudioChannelID != id) {
AudioChannelID = id;
// Syncword - 0x0B77
if (data[0] == 0x0B && data[1] == 0x77) {
if (AudioCodecID != CODEC_ID_AC3) {
Debug(3, "[softhddev]%s: AC-3 %d\n", __FUNCTION__, id);
CodecAudioClose(MyAudioDecoder);
CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_AC3);
AudioCodecID = CODEC_ID_AC3;
}
AudioRawAc3 = 1;
// Syncword - 0xFFFC - 0xFFFF
} else if (data[0] == 0xFF && (data[1] & 0xFC) == 0xFC) {
if (AudioCodecID != CODEC_ID_MP2) {
Debug(3, "[softhddev]%s: MP2 %d\n", __FUNCTION__, id);
CodecAudioClose(MyAudioDecoder);
CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_MP2);
AudioCodecID = CODEC_ID_MP2;
}
// latm header 0x56E0 11bits: 0x2B7
} else if (data[0] == 0x56 && (data[1] & 0xE0) == 0xE0
&& (((data[1] & 0x1F) << 8) + (data[2] & 0xFF)) < size) {
if (AudioCodecID != CODEC_ID_AAC_LATM) {
#if 0
// test harder check
printf("%d %d\n", (((data[1] & 0x1F) << 8) + (data[2] & 0xFF)),
size);
printf("%p %x %x\n", data,
data[3 + (((data[1] & 0x1F) << 8) + (data[2] & 0xFF))],
data[4 + (((data[1] & 0x1F) << 8) + (data[2] & 0xFF))]);
#endif
Debug(3, "[softhddev]%s: AAC LATM %d\n", __FUNCTION__, id);
CodecAudioClose(MyAudioDecoder);
CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_AAC_LATM);
AudioCodecID = CODEC_ID_AAC_LATM;
}
// Private stream + DVD Track ID Syncword - 0x0B77
} else if (data[-n - 9 + 3] == 0xBD && (data[0] & 0xF0) == 0x80
&& data[4] == 0x0B && data[5] == 0x77) {
if (AudioCodecID != CODEC_ID_AC3) {
Debug(3, "[softhddev]%s: DVD Audio %d\n", __FUNCTION__, id);
CodecAudioClose(MyAudioDecoder);
CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_AC3);
AudioCodecID = CODEC_ID_AC3;
}
AudioRawAc3 = 0;
// Private stream + LPCM ID
} else if (data[-n - 9 + 3] == 0xBD && data[0] == 0xA0) {
if (AudioCodecID != CODEC_ID_PCM_DVD) {
static int samplerates[] = { 48000, 96000, 44100, 32000 };
int samplerate;
int channels;
int bits_per_sample;
avpkt->pts = AV_NOPTS_VALUE;
CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_MP2);
AudioCodecID = CODEC_ID_MP2;
data += n;
size -= n;
Debug(3, "[softhddev]%s: LPCM %d sr:%d bits:%d chan:%d\n",
__FUNCTION__, id, data[5] >> 4,
(((data[5] >> 6) & 0x3) + 4) * 4, (data[5] & 0x7) + 1);
CodecAudioClose(MyAudioDecoder);
bits_per_sample = (((data[5] >> 6) & 0x3) + 4) * 4;
if (bits_per_sample != 16) {
Error(_
("softhddev: LPCM %d bits per sample aren't supported\n"),
bits_per_sample);
// FIXME: handle unsupported formats.
}
samplerate = samplerates[data[5] >> 4];
channels = (data[5] & 0x7) + 1;
AudioSetup(&samplerate, &channels, 0);
if (samplerate != samplerates[data[5] >> 4]) {
Error(_("softhddev: LPCM %d sample-rate is unsupported\n"),
samplerates[data[5] >> 4]);
// FIXME: support resample
}
if (channels != (data[5] & 0x7) + 1) {
Error(_("softhddev: LPCM %d channels are unsupported\n"),
(data[5] & 0x7) + 1);
// FIXME: support resample
}
//CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_PCM_DVD);
AudioCodecID = CODEC_ID_PCM_DVD;
}
} else {
// no start package
// FIXME: Nick/Viva sends this shit, need to find sync in packet
// FIXME: otherwise it takes too long until sound appears
if (AudioCodecID == CODEC_ID_NONE) {
int codec_id;
Debug(3, "[softhddev]%s: ??? %d\n", __FUNCTION__, id);
avpkt->data = (void *)data;
avpkt->size = size;
if (AudioChannelID == 0xBD) {
n = FindDolbySync(avpkt);
codec_id = CODEC_ID_AC3;
AudioRawAc3 = 1;
} else if (0xC0 <= AudioChannelID && AudioChannelID <= 0xDF) {
n = FindAudioSync(avpkt);
codec_id = CODEC_ID_MP2;
} else {
n = -1;
}
if (n < 0) {
return osize;
}
CodecAudioOpen(MyAudioDecoder, NULL, codec_id);
AudioCodecID = codec_id;
data += n;
size -= n;
avpkt->pts = AV_NOPTS_VALUE;
}
}
// no decoder or codec known
// still no decoder or codec known
if (AudioCodecID == CODEC_ID_NONE) {
return osize;
}
}
// convert data, if needed for ffmpeg
if (AudioCodecID == CODEC_ID_AC3 && !AudioRawAc3
&& (data[0] & 0xF0) == 0x80) {
avpkt->data = (void *)data + 4; // skip track header
avpkt->size = size - 4;
if (avpkt->pts != (int64_t) AV_NOPTS_VALUE) {
avpkt->pts += 200 * 90; // FIXME: needs bigger buffer
}
CodecAudioDecode(MyAudioDecoder, avpkt);
} else if (AudioCodecID == CODEC_ID_PCM_DVD) {
if (size > 7) {
char *buf;
avpkt->data = (void *)data;
avpkt->size = size;
//memset(avpkt->data + avpkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
CodecAudioDecode(MyAudioDecoder, avpkt);
if (avpkt->pts != (int64_t) AV_NOPTS_VALUE) {
// FIXME: needs bigger buffer
AudioSetClock(avpkt->pts + 200 * 90);
}
if (!(buf = malloc(size - 7))) {
Error(_("softhddev: out of memory\n"));
} else {
swab(data + 7, buf, size - 7);
AudioEnqueue(buf, size - 7);
free(buf);
}
}
} else {
avpkt->data = (void *)data;
avpkt->size = size;
CodecAudioDecode(MyAudioDecoder, avpkt);
}
return osize;
}
/**
** Mute audio device.
** Turns off audio while replaying.
*/
void Mute(void)
{
SkipAudio = 1;
AudioFlushBuffers();
//AudioSetVolume(0);
}
@@ -423,6 +581,7 @@ static void VideoEnqueue(int64_t pts, const void *data, int size)
// new + grow reserves FF_INPUT_BUFFER_PADDING_SIZE
av_grow_packet(avpkt, ((size + VIDEO_BUFFER_SIZE / 2)
/ (VIDEO_BUFFER_SIZE / 2)) * (VIDEO_BUFFER_SIZE / 2));
// FIXME: out of memory!
#ifdef DEBUG
if (avpkt->size <= avpkt->stream_index + size) {
fprintf(stderr, "%d %d %d\n", avpkt->size, avpkt->stream_index,
@@ -443,6 +602,19 @@ static void VideoEnqueue(int64_t pts, const void *data, int size)
#endif
}
/**
** Reset current packet.
*/
static void VideoResetPacket(void)
{
AVPacket *avpkt;
avpkt = &VideoPacketRb[VideoPacketWrite];
avpkt->stream_index = 0;
avpkt->pts = AV_NOPTS_VALUE;
avpkt->dts = AV_NOPTS_VALUE;
}
/**
** Finish current packet advance to next.
**
@@ -481,10 +653,7 @@ static void VideoNextPacket(int codec_id)
VideoDisplayWakeup();
// intialize next package to use
avpkt = &VideoPacketRb[VideoPacketWrite];
avpkt->stream_index = 0;
avpkt->pts = AV_NOPTS_VALUE;
avpkt->dts = AV_NOPTS_VALUE;
VideoResetPacket();
}
/**
@@ -541,7 +710,7 @@ int VideoDecode(void)
int saved_size;
static int last_codec_id = CODEC_ID_NONE;
if (VideoFreezed) {
if (StreamFreezed) { // stream freezed
return 1;
}
if (VideoClearBuffers) {
@@ -746,6 +915,8 @@ int PlayVideo(const uint8_t * data, int size)
const uint8_t *check;
int64_t pts;
int n;
int z;
int l;
if (Usr1Signal) { // x11 server ready
Usr1Signal = 0;
@@ -757,7 +928,7 @@ int PlayVideo(const uint8_t * data, int size)
if (SkipVideo) { // skip video
return size;
}
if (VideoFreezed) { // video freezed
if (StreamFreezed) { // stream freezed
return 0;
}
if (NewVideoStream) { // channel switched
@@ -820,9 +991,71 @@ int PlayVideo(const uint8_t * data, int size)
check = data + 9 + n;
if (0) {
printf("%02x: %02x %02x %02x %02x %02x\n", data[6], check[0], check[1],
check[2], check[3], check[4]);
printf("%02x: %02x %02x %02x %02x %02x %02x %02x\n", data[6], check[0],
check[1], check[2], check[3], check[4], check[5], check[6]);
}
#if 1 // FIXME: test code for better h264 detection
z = 0;
l = size - 9 - n;
while (!*check) { // count leading zeros
if (--l < 4) {
Warning(_("[softhddev] empty video packet %d bytes\n"), size);
return size;
}
++check;
++z;
}
// H264 Access Unit Delimiter 0x00 0x00 0x00 0x01 0x09
if ((data[6] & 0xC0) == 0x80 && z > 2 && check[0] == 0x01
&& check[1] == 0x09) {
if (VideoCodecID == CODEC_ID_H264) {
VideoNextPacket(CODEC_ID_H264);
} else {
Debug(3, "video: h264 detected\n");
VideoCodecID = CODEC_ID_H264;
}
// SKIP PES header
VideoEnqueue(pts, check - 3, l + 3);
return size;
}
// PES start code 0x00 0x00 0x01
if (z > 1 && check[0] == 0x01) {
if (VideoCodecID == CODEC_ID_MPEG2VIDEO) {
VideoNextPacket(CODEC_ID_MPEG2VIDEO);
} else {
Debug(3, "video: mpeg2 detected ID %02x\n", check[3]);
VideoCodecID = CODEC_ID_MPEG2VIDEO;
}
#ifdef DEBUG
if (ValidateMpeg(data, size)) {
Debug(3, "softhddev/video: invalid mpeg2 video packet\n");
}
#endif
// SKIP PES header
VideoEnqueue(pts, check - 2, l + 2);
return size;
}
// this happens when vdr sends incomplete packets
if (VideoCodecID == CODEC_ID_NONE) {
Debug(3, "video: not detected\n");
return size;
}
// SKIP PES header
VideoEnqueue(pts, data + 9 + n, size - 9 - n);
// incomplete packets produce artefacts after channel switch
// packet < 65526 is the last split packet, detect it here for
// better latency
if (size < 65526 && VideoCodecID == CODEC_ID_MPEG2VIDEO) {
// mpeg codec supports incomplete packets
// waiting for a full complete packages, increases needed delays
VideoNextPacket(CODEC_ID_MPEG2VIDEO);
}
return size;
#else
// FIXME: no valid mpeg2/h264 detection yet
// FIXME: better skip all zero's >3 && 0x01 0x09 h264, >2 && 0x01 -> mpeg2
@@ -881,10 +1114,26 @@ int PlayVideo(const uint8_t * data, int size)
VideoEnqueue(pts, check, size - 9 - n);
return size;
#endif
}
#ifdef USE_JPEG
/// call VDR support function
extern uint8_t *CreateJpeg(uint8_t *, int *, int, int, int);
#if defined(USE_JPEG) && JPEG_LIB_VERSION >= 80
/**
** Create a jpeg image in memory.
**
** @param image raw RGB image
** @param raw_size size of raw image
** @param size[out] size of jpeg image
** @param quality jpeg quality
** @param width number of horizontal pixels in image
** @param height number of vertical pixels in image
**
** @returns allocated jpeg image.
*/
uint8_t *CreateJpeg(uint8_t * image, int raw_size, int *size, int quality,
int width, int height)
{
@@ -937,21 +1186,15 @@ uint8_t *CreateJpeg(uint8_t * image, int raw_size, int *size, int quality,
uint8_t *GrabImage(int *size, int jpeg, int quality, int width, int height)
{
if (jpeg) {
#ifdef USE_JPEG
int raw_size;
uint8_t *image;
uint8_t *jpg_image;
uint8_t *image;
int raw_size = 0;
raw_size = 0;
image = VideoGrab(&raw_size, &width, &height, 0);
jpg_image = CreateJpeg(image, raw_size, size, quality, width, height);
jpg_image = CreateJpeg(image, size, quality, width, height);
free(image);
return jpg_image;
#else
(void)quality;
Error(_("softhddev: jpeg grabbing not supported\n"));
return NULL;
#endif
}
if (width != -1 && height != -1) {
Warning(_("softhddev: scaling unsupported\n"));
@@ -982,9 +1225,7 @@ void SetPlayMode(void)
NewAudioStream = 1;
}
}
VideoFreezed = 0;
SkipAudio = 0;
SkipVideo = 0;
StreamFreezed = 0;
}
/**
@@ -994,10 +1235,11 @@ void Clear(void)
{
int i;
VideoNextPacket(VideoCodecID); // terminate work
VideoResetPacket(); // terminate work
VideoClearBuffers = 1;
// FIXME: avcodec_flush_buffers
AudioFlushBuffers();
//NewAudioStream = 1;
// FIXME: audio avcodec_flush_buffers, video is done by VideoClearBuffers
for (i = 0; VideoClearBuffers && i < 20; ++i) {
usleep(1 * 1000);
@@ -1009,9 +1251,9 @@ void Clear(void)
*/
void Play(void)
{
VideoFreezed = 0;
StreamFreezed = 0;
SkipAudio = 0;
// FIXME: restart audio
AudioPlay();
}
/**
@@ -1019,13 +1261,15 @@ void Play(void)
*/
void Freeze(void)
{
VideoFreezed = 1;
// FIXME: freeze audio
AudioFlushBuffers();
StreamFreezed = 1;
AudioPause();
}
/**
** Display the given I-frame as a still picture.
**
** @param data pes frame data
** @param size number of bytes in frame
*/
void StillPicture(const uint8_t * data, int size)
{
@@ -1038,10 +1282,10 @@ void StillPicture(const uint8_t * data, int size)
Error(_("[softhddev] invalid still video packet\n"));
return;
}
if (VideoCodecID == CODEC_ID_NONE) {
// FIXME: should detect codec, see PlayVideo
Error(_("[softhddev] no codec known for still picture\n"));
return;
}
//Clear(); // flush video buffers
@@ -1051,28 +1295,42 @@ void StillPicture(const uint8_t * data, int size)
const uint8_t *split;
int n;
// split the I-frame into single pes packets
split = data;
n = size;
do {
int len;
if ((data[3] & 0xF0) == 0xE0) { // PES packet
split = data;
n = size;
// split the I-frame into single pes packets
do {
int len;
len = (split[4] << 8) + split[5];
if (len > n) {
break;
len = (split[4] << 8) + split[5];
if (!len || len + 6 > n) {
PlayVideo(split, n); // feed remaining bytes
break;
}
PlayVideo(split, len + 6); // feed it
split += 6 + len;
n -= 6 + len;
} while (n > 6);
VideoNextPacket(VideoCodecID); // terminate last packet
if (VideoCodecID == CODEC_ID_H264) {
VideoEnqueue(AV_NOPTS_VALUE, seq_end_h264,
sizeof(seq_end_h264));
} else {
VideoEnqueue(AV_NOPTS_VALUE, seq_end_mpeg,
sizeof(seq_end_mpeg));
}
PlayVideo(split, len + 6); // feed it
split += 6 + len;
n -= 6 + len;
} while (n > 6);
VideoNextPacket(VideoCodecID); // terminate last packet
VideoNextPacket(VideoCodecID); // terminate last packet
} else { // ES packet
if (VideoCodecID == CODEC_ID_H264) {
VideoEnqueue(AV_NOPTS_VALUE, seq_end_h264, sizeof(seq_end_h264));
} else {
if (VideoCodecID != CODEC_ID_MPEG2VIDEO) {
VideoNextPacket(CODEC_ID_NONE); // close last stream
VideoCodecID = CODEC_ID_MPEG2VIDEO;
}
VideoEnqueue(AV_NOPTS_VALUE, data, size);
VideoEnqueue(AV_NOPTS_VALUE, seq_end_mpeg, sizeof(seq_end_mpeg));
VideoNextPacket(VideoCodecID); // terminate last packet
}
VideoNextPacket(VideoCodecID); // terminate last packet
}
}
@@ -1085,13 +1343,12 @@ int Poll(int timeout)
{
// buffers are too full
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX / 2) {
if (timeout) {
// let display thread work
if (timeout) { // let display thread work
usleep(timeout * 1000);
}
return atomic_read(&VideoPacketsFilled) < VIDEO_PACKET_MAX / 2;
}
return 0;
return 1;
}
/**
@@ -1161,11 +1418,16 @@ void OsdDrawARGB(int x, int y, int height, int width, const uint8_t * argb)
const char *CommandLineHelp(void)
{
return " -a device\taudio device (fe. alsa: hw:0,0 oss: /dev/dsp)\n"
" -p device\taudio device (alsa only) for pass-through (hw:0,1)\n"
" -p device\taudio device for pass-through (hw:0,1 or /dev/dsp1)\n"
" -c channel\taudio mixer channel name (fe. PCM)\n"
" -d display\tdisplay of x11 server (fe. :0.0)\n"
" -f\t\tstart with fullscreen window (only with window manager)\n"
" -g geometry\tx11 window geometry wxh+x+y\n"
" -x\t\tstart x11 server\n" " -s\t\tstart in suspended mode\n";
" -s\t\tstart in suspended mode\n" " -x\t\tstart x11 server\n"
" -w workaround\tenable/disable workarounds\n"
"\tno-hw-decoder\t\tdisable hw decoder, use software decoder only\n"
"\tno-mpeg-hw-decoder\tdisable hw decoder for mpeg only\n"
"\talsa-driver-broken\tdisable broken alsa driver message\n";
}
/**
@@ -1180,10 +1442,13 @@ int ProcessArgs(int argc, char *const argv[])
// Parse arguments.
//
for (;;) {
switch (getopt(argc, argv, "-a:p:d:fg:xs")) {
case 'a': // audio device
switch (getopt(argc, argv, "-a:c:d:fg:p:sw:x")) {
case 'a': // audio device for pcm
AudioSetDevice(optarg);
continue;
case 'c': // channel of audio mixer
AudioSetChannel(optarg);
continue;
case 'p': // pass-through audio device
AudioSetDeviceAC3(optarg);
continue;
@@ -1207,6 +1472,17 @@ int ProcessArgs(int argc, char *const argv[])
case 's': // start in suspend mode
ConfigStartSuspended = 1;
continue;
case 'w': // workarounds
if (!strcasecmp("no-hw-decoder", optarg)) {
} else if (!strcasecmp("no-mpeg-hw-decoder", optarg)) {
} else if (!strcasecmp("alsa-driver-broken", optarg)) {
AudioAlsaDriverBroken = 1;
} else {
fprintf(stderr, _("Workaround '%s' unsupported\n"),
optarg);
return 0;
}
continue;
case EOF:
break;
case '-':
@@ -1338,7 +1614,7 @@ void SoftHdDeviceExit(void)
StopVideo();
CodecExit();
VideoPacketExit();
//VideoPacketExit();
if (ConfigStartX11Server) {
Debug(3, "x-setup: Stop x11 server\n");

View File

@@ -42,7 +42,7 @@ extern "C"
//////////////////////////////////////////////////////////////////////////////
static const char *const VERSION = "0.4.6";
static const char *const VERSION = "0.4.8";
static const char *const DESCRIPTION =
trNOOP("A software and GPU emulated HD device");
@@ -62,6 +62,7 @@ static char ConfigMakePrimary; ///< config primary wanted
static char ConfigHideMainMenuEntry; ///< config hide main menu entry
static int ConfigVideoSkipLines; ///< config skip lines top/bottom
static int ConfigVideoStudioLevels; ///< config use studio levels
/// config deinterlace
static int ConfigVideoDeinterlace[RESOLUTIONS];
@@ -69,6 +70,9 @@ static int ConfigVideoDeinterlace[RESOLUTIONS];
/// config skip chroma
static int ConfigVideoSkipChromaDeinterlace[RESOLUTIONS];
/// config inverse telecine
static int ConfigVideoInverseTelecine[RESOLUTIONS];
/// config denoise
static int ConfigVideoDenoise[RESOLUTIONS];
@@ -148,9 +152,34 @@ class cSoftOsd:public cOsd
cSoftOsd(int, int, uint);
virtual ~ cSoftOsd(void);
virtual void Flush(void);
// virtual void SetActive(bool);
virtual void SetActive(bool);
};
static volatile char OsdDirty; ///< flag force redraw everything
/**
** Sets this OSD to be the active one.
**
** @param on true on, false off
**
** @note only needed as workaround for text2skin plugin with
** undrawn areas.
*/
void cSoftOsd::SetActive(bool on)
{
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, on);
if (Active() == on) {
return; // already active, no action
}
cOsd::SetActive(on);
if (on) {
OsdDirty = 1;
} else {
OsdClose();
}
}
cSoftOsd::cSoftOsd(int left, int top, uint level)
:cOsd(left, top, level)
{
@@ -167,6 +196,7 @@ cSoftOsd::~cSoftOsd(void)
{
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
SetActive(false);
// done by SetActive: OsdClose();
#ifdef USE_YAEPG
// support yaepghd, video window
@@ -180,12 +210,11 @@ cSoftOsd::~cSoftOsd(void)
VideoSetOutputPosition(0, 0, width, height);
}
#endif
OsdClose();
}
///
/// Actually commits all data to the OSD hardware.
///
/**
** Actually commits all data to the OSD hardware.
*/
void cSoftOsd::Flush(void)
{
cPixmapMemory *pm;
@@ -228,43 +257,32 @@ void cSoftOsd::Flush(void)
int y2;
// get dirty bounding box
if (!bitmap->Dirty(x1, y1, x2, y2)) {
if (OsdDirty) { // forced complete update
x1 = 0;
y1 = 0;
x2 = bitmap->Width() - 1;
y2 = bitmap->Height() - 1;
} else if (!bitmap->Dirty(x1, y1, x2, y2)) {
continue; // nothing dirty continue
}
#if 0
// FIXME: need only to convert and upload dirty areas
// DrawBitmap(bitmap);
w = bitmap->Width();
h = bitmap->Height();
argb = (uint8_t *) malloc(w * h * sizeof(uint32_t));
for (y = 0; y < h; ++y) {
for (x = 0; x < w; ++x) {
((uint32_t *) argb)[x + y * w] = bitmap->GetColor(x, y);
}
}
// check if subtitles
if (this->Level == OSD_LEVEL_SUBTITLES) {
int video_width;
int video_height;
if (0) {
dsyslog("[softhddev]%s: subtitle %d, %d\n", __FUNCTION__,
Left() + bitmap->X0(), Top() + bitmap->Y0());
}
video_width = 1920;
video_height = 1080;
OsdDrawARGB((1920 - video_width) / 2 + Left() + bitmap->X0(),
1080 - video_height + Top() + bitmap->Y0(), w, h, argb);
} else {
OsdDrawARGB(Left() + bitmap->X0(), Top() + bitmap->Y0(), w, h,
argb);
}
#else
// convert and upload only dirty areas
w = x2 - x1 + 1;
h = y2 - y1 + 1;
if (1) { // just for the case it makes trouble
int width;
int height;
double video_aspect;
::GetOsdSize(&width, &height, &video_aspect);
if (w > width) {
w = width;
x2 = x1 + width - 1;
}
if (h > height) {
h = height;
y2 = y1 + height - 1;
}
}
#ifdef DEBUG
if (w > bitmap->Width() || h > bitmap->Height()) {
esyslog(tr("softhdev: dirty area too big\n"));
@@ -278,14 +296,14 @@ void cSoftOsd::Flush(void)
bitmap->GetColor(x, y);
}
}
// check if subtitles
OsdDrawARGB(Left() + bitmap->X0() + x1, Top() + bitmap->Y0() + y1,
w, h, argb);
#endif
bitmap->Clean();
// FIXME: reuse argb
free(argb);
}
OsdDirty = 0;
return;
}
@@ -330,6 +348,10 @@ cOsd *cSoftOsdProvider::Osd; ///< single osd
/**
** Create a new OSD.
**
** @param left x-coordinate of OSD
** @param top y-coordinate of OSD
** @param level layer level of OSD
*/
cOsd *cSoftOsdProvider::CreateOsd(int left, int top, uint level)
{
@@ -366,9 +388,11 @@ class cMenuSetupSoft:public cMenuSetupPage
int MakePrimary;
int HideMainMenuEntry;
int SkipLines;
int StudioLevels;
int Scaling[RESOLUTIONS];
int Deinterlace[RESOLUTIONS];
int SkipChromaDeinterlace[RESOLUTIONS];
int InverseTelecine[RESOLUTIONS];
int Denoise[RESOLUTIONS];
int Sharpen[RESOLUTIONS];
int AudioDelay;
@@ -405,7 +429,8 @@ static inline cOsdItem *SeparatorItem(const char *label)
cMenuSetupSoft::cMenuSetupSoft(void)
{
static const char *const deinterlace[] = {
"Bob", "Weave/None", "Temporal", "TemporalSpatial", "Software"
"Bob", "Weave/None", "Temporal", "TemporalSpatial", "Software Bob",
"Software Spatial",
};
static const char *const scaling[] = {
"Normal", "Fast", "HQ", "Anamorphic"
@@ -434,17 +459,23 @@ cMenuSetupSoft::cMenuSetupSoft(void)
SkipLines = ConfigVideoSkipLines;
Add(new cMenuEditIntItem(tr("Skip lines top+bot (pixel)"), &SkipLines, 0,
64));
StudioLevels = ConfigVideoStudioLevels;
Add(new cMenuEditBoolItem(tr("Use studio levels (vdpau only)"),
&StudioLevels, trVDR("no"), trVDR("yes")));
for (i = 0; i < RESOLUTIONS; ++i) {
Add(SeparatorItem(resolution[i]));
Scaling[i] = ConfigVideoScaling[i];
Add(new cMenuEditStraItem(tr("Scaling"), &Scaling[i], 4, scaling));
Deinterlace[i] = ConfigVideoDeinterlace[i];
Add(new cMenuEditStraItem(tr("Deinterlace"), &Deinterlace[i], 5,
Add(new cMenuEditStraItem(tr("Deinterlace"), &Deinterlace[i], 6,
deinterlace));
SkipChromaDeinterlace[i] = ConfigVideoSkipChromaDeinterlace[i];
Add(new cMenuEditBoolItem(tr("SkipChromaDeinterlace (vdpau)"),
&SkipChromaDeinterlace[i], trVDR("no"), trVDR("yes")));
InverseTelecine[i] = ConfigVideoInverseTelecine[i];
Add(new cMenuEditBoolItem(tr("Inverse Telecine (vdpau)"),
&InverseTelecine[i], trVDR("no"), trVDR("yes")));
Denoise[i] = ConfigVideoDenoise[i];
Add(new cMenuEditIntItem(tr("Denoise (0..1000) (vdpau)"), &Denoise[i],
0, 1000));
@@ -500,6 +531,8 @@ void cMenuSetupSoft::Store(void)
SetupStore("SkipLines", ConfigVideoSkipLines = SkipLines);
VideoSetSkipLines(ConfigVideoSkipLines);
SetupStore("StudioLevels", ConfigVideoStudioLevels = StudioLevels);
VideoSetStudioLevels(ConfigVideoStudioLevels);
for (i = 0; i < RESOLUTIONS; ++i) {
char buf[128];
@@ -512,6 +545,8 @@ void cMenuSetupSoft::Store(void)
"SkipChromaDeinterlace");
SetupStore(buf, ConfigVideoSkipChromaDeinterlace[i] =
SkipChromaDeinterlace[i]);
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "InverseTelecine");
SetupStore(buf, ConfigVideoInverseTelecine[i] = InverseTelecine[i]);
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Denoise");
SetupStore(buf, ConfigVideoDenoise[i] = Denoise[i]);
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Sharpen");
@@ -520,6 +555,7 @@ void cMenuSetupSoft::Store(void)
VideoSetScaling(ConfigVideoScaling);
VideoSetDeinterlace(ConfigVideoDeinterlace);
VideoSetSkipChromaDeinterlace(ConfigVideoSkipChromaDeinterlace);
VideoSetInverseTelecine(ConfigVideoInverseTelecine);
VideoSetDenoise(ConfigVideoDenoise);
VideoSetSharpen(ConfigVideoSharpen);
@@ -572,9 +608,8 @@ cSoftHdPlayer::~cSoftHdPlayer()
*/
class cSoftHdControl:public cControl
{
private:
cSoftHdPlayer * Player;
public:
static cSoftHdPlayer *Player; ///< dummy player
virtual void Hide(void)
{
}
@@ -585,6 +620,13 @@ class cSoftHdControl:public cControl
virtual ~ cSoftHdControl();
};
cSoftHdPlayer *cSoftHdControl::Player;
/**
** Handle a key event.
**
** @param key key pressed
*/
eOSState cSoftHdControl::ProcessKey(eKeys key)
{
if (!ISMODELESSKEY(key) || key == kBack || key == kStop) {
@@ -592,8 +634,8 @@ eOSState cSoftHdControl::ProcessKey(eKeys key)
delete Player;
Player = NULL;
Resume();
}
Resume();
return osEnd;
}
return osContinue;
@@ -632,7 +674,6 @@ class cSoftHdDevice:public cDevice
virtual void Play(void);
virtual void Freeze(void);
virtual void Mute(void);
virtual void SetVolumeDevice(int);
virtual void StillPicture(const uchar *, int);
virtual bool Poll(cPoller &, int = 0);
virtual bool Flush(int = 0);
@@ -650,6 +691,7 @@ class cSoftHdDevice:public cDevice
virtual int GetAudioChannelDevice(void);
virtual void SetDigitalAudioDevice(bool);
virtual void SetAudioTrackDevice(eTrackType);
virtual void SetVolumeDevice(int);
virtual int PlayAudio(const uchar *, int, uchar);
// Image Grab facilities
@@ -675,6 +717,7 @@ cSoftHdDevice::cSoftHdDevice(void)
#if 0
spuDecoder = NULL;
#endif
SetVideoDisplayFormat(eVideoDisplayFormat(Setup.VideoDisplayFormat));
}
cSoftHdDevice::~cSoftHdDevice(void)
@@ -801,6 +844,9 @@ void cSoftHdDevice::Freeze(void)
::Freeze();
}
/**
** Turns off audio while replaying.
*/
void cSoftHdDevice::Mute(void)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
@@ -809,13 +855,6 @@ void cSoftHdDevice::Mute(void)
::Mute();
}
void cSoftHdDevice::SetVolumeDevice(int volume)
{
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, volume);
::SetVolumeDevice(volume);
}
/**
** Display the given I-frame as a still picture.
*/
@@ -864,21 +903,23 @@ bool cSoftHdDevice::Flush(int timeout_ms)
** Sets the video display format to the given one (only useful if this
** device has an MPEG decoder).
**
** @note FIXME: this function isn't called on the initial channel
** @note this function isn't called on the initial channel
*/
void cSoftHdDevice::
SetVideoDisplayFormat(eVideoDisplayFormat video_display_format)
void cSoftHdDevice::SetVideoDisplayFormat(
eVideoDisplayFormat video_display_format)
{
static int last = -1;
cDevice::SetVideoDisplayFormat(video_display_format);
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, video_display_format);
cDevice::SetVideoDisplayFormat(video_display_format);
// called on every channel switch, no need to kill osd...
if (last != video_display_format) {
last = video_display_format;
::VideoSetDisplayFormat(video_display_format);
OsdDirty = 1;
}
}
@@ -938,11 +979,23 @@ int cSoftHdDevice::GetAudioChannelDevice(void)
return 0;
}
/**
** Sets the audio volume on this device (Volume = 0...255).
**
** @param volume device volume
*/
void cSoftHdDevice::SetVolumeDevice(int volume)
{
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, volume);
::SetVolumeDevice(volume);
}
// ----------------------------------------------------------------------------
///
/// Play a video packet.
///
/**
** Play a video packet.
*/
int cSoftHdDevice::PlayVideo(const uchar * data, int length)
{
//dsyslog("[softhddev]%s: %p %d\n", __FUNCTION__, data, length);
@@ -997,6 +1050,16 @@ uchar *cSoftHdDevice::GrabImage(int &size, bool jpeg, int quality, int width,
return::GrabImage(&size, jpeg, quality, width, height);
}
/**
** Call rgb to jpeg for C Plugin.
*/
extern "C" uint8_t * CreateJpeg(uint8_t * image, int *size, int quality,
int width, int height)
{
return (uint8_t *) RgbToJpeg((uchar *) image, width, height, *size,
quality);
}
//////////////////////////////////////////////////////////////////////////////
// cPlugin
//////////////////////////////////////////////////////////////////////////////
@@ -1142,12 +1205,14 @@ cOsdObject *cPluginSoftHdDevice::MainMenuAction(void)
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
//MyDevice->StopReplay();
cControl::Launch(new cSoftHdControl);
cControl::Attach();
Suspend(ConfigSuspendClose, ConfigSuspendClose, ConfigSuspendX11);
if (ShutdownHandler.GetUserInactiveTime()) {
dsyslog("[softhddev]%s: set user inactive\n", __FUNCTION__);
ShutdownHandler.SetUserInactive();
if (!cSoftHdControl::Player) { // not already suspended
cControl::Launch(new cSoftHdControl);
cControl::Attach();
Suspend(ConfigSuspendClose, ConfigSuspendClose, ConfigSuspendX11);
if (ShutdownHandler.GetUserInactiveTime()) {
dsyslog("[softhddev]%s: set user inactive\n", __FUNCTION__);
ShutdownHandler.SetUserInactive();
}
}
return NULL;
@@ -1211,6 +1276,10 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
VideoSetSkipLines(ConfigVideoSkipLines = atoi(value));
return true;
}
if (!strcmp(name, "StudioLevels")) {
VideoSetStudioLevels(ConfigVideoStudioLevels = atoi(value));
return true;
}
for (i = 0; i < RESOLUTIONS; ++i) {
char buf[128];
@@ -1233,6 +1302,12 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
VideoSetSkipChromaDeinterlace(ConfigVideoSkipChromaDeinterlace);
return true;
}
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "InverseTelecine");
if (!strcmp(name, buf)) {
ConfigVideoInverseTelecine[i] = atoi(value);
VideoSetInverseTelecine(ConfigVideoInverseTelecine);
return true;
}
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Denoise");
if (!strcmp(name, buf)) {
ConfigVideoDenoise[i] = atoi(value);
@@ -1324,6 +1399,10 @@ cString cPluginSoftHdDevice::SVDRPCommand(const char *command,
__attribute__ ((unused)) int &reply_code)
{
if (!strcasecmp(command, "SUSP")) {
if (cSoftHdControl::Player) { // already suspended
return "SoftHdDevice already suspended";
}
// should be after suspend, but SetPlayMode resumes
cControl::Launch(new cSoftHdControl);
cControl::Attach();
Suspend(ConfigSuspendClose, ConfigSuspendClose, ConfigSuspendX11);
@@ -1333,8 +1412,10 @@ cString cPluginSoftHdDevice::SVDRPCommand(const char *command,
if (ShutdownHandler.GetUserInactiveTime()) {
ShutdownHandler.SetUserInactiveTimeout();
}
if (cSoftHdControl::Player) { // suspended
cControl::Shutdown(); // not need, if not suspended
}
Resume();
cControl::Shutdown(); // not need, if not suspended
return "SoftHdDevice is resumed";
}
return NULL;

View File

@@ -23,19 +23,19 @@ SLOT="0"
KEYWORDS="~x86 ~amd64"
IUSE="vaapi vdpau alsa oss yaepg opengl jpeg"
DEPEND=">=x11-libs/libxcb-1.7
DEPEND=">=x11-libs/libxcb-1.8
x11-libs/xcb-util
x11-libs/xcb-util-wm
x11-libs/xcb-util-keysyms
x11-libs/xcb-util-renderutil
x11-libs/libX11
opengl? ( virtual/opengl )
>=media-video/ffmpeg-0.7
>=virtual/ffmpeg-0.7
sys-devel/gettext
sys-devel/make
dev-util/pkgconfig
yaepg? ( >=media-video/vdr-1.7[yaepg] )
!yaepg? ( >=media-video/vdr-1.7 )
yaepg? ( >=media-video/vdr-1.7.23[yaepg] )
!yaepg? ( >=media-video/vdr-1.7.23 )
vdpau? ( x11-libs/libvdpau )
vaapi? ( x11-libs/libva )
alsa? ( media-libs/alsa-lib )
@@ -64,10 +64,11 @@ src_compile() {
src_install() {
vdr-plugin_src_install
dodir /etc/vdr/plugins || die
dodoc README.txt
insinto /etc/vdr/plugins
fowners -R vdr:vdr /etc/vdr || die
#dodir /etc/vdr/plugins || die
#insinto /etc/vdr/plugins
#fowners -R vdr:vdr /etc/vdr || die
#insinto /etc/conf.d
#doins vdr.softhddevice

711
video.c

File diff suppressed because it is too large Load Diff

View File

@@ -92,6 +92,9 @@ extern void VideoSetDeinterlace(int[]);
/// Set skip chroma deinterlace.
extern void VideoSetSkipChromaDeinterlace(int[]);
/// Set inverse telecine.
extern void VideoSetInverseTelecine(int[]);
/// Set scaling.
extern void VideoSetScaling(int[]);
@@ -104,6 +107,9 @@ extern void VideoSetSharpen(int[]);
/// Set skip lines.
extern void VideoSetSkipLines(int);
/// Set studio levels.
extern void VideoSetStudioLevels(int);
/// Set audio delay.
extern void VideoSetAudioDelay(int);