mirror of
https://projects.vdr-developer.org/git/vdr-plugin-softhddevice.git
synced 2023-10-10 17:16:51 +00:00
Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7f0cf6d6f | ||
|
|
346953d209 | ||
|
|
97af9c6de2 | ||
|
|
8dd95dab5e | ||
|
|
6775173e4f | ||
|
|
9170fcf485 | ||
|
|
919428cb80 | ||
|
|
4331692ee5 | ||
|
|
5aa826bdb0 | ||
|
|
6736db082e | ||
|
|
807b4df381 | ||
| 56edfd4f54 | |||
|
|
0a1a258d2a | ||
|
|
09a0880d07 | ||
|
|
a98a4adc7e | ||
|
|
f872f54e2a | ||
| 33c638d538 | |||
|
|
0a2a221fa9 | ||
|
|
24a065e5de | ||
|
|
6df970ca9e | ||
|
|
616cd9e133 | ||
|
|
a91533f6d1 | ||
|
|
baa4500a2c | ||
|
|
f28a737a9a | ||
|
|
19cec561ba | ||
|
|
d8f63adaad | ||
|
|
8c16466d31 | ||
|
|
ced54a5cf1 | ||
|
|
08246b5ac3 | ||
|
|
c3a1de8c7b | ||
|
|
918170d00b | ||
|
|
bc50f37c4d | ||
|
|
09cf1f5c85 | ||
|
|
947f6b312e | ||
|
|
99728258f1 | ||
|
|
c972f8c4dd | ||
|
|
7d38dff5bf | ||
|
|
8db8b68edd |
53
ChangeLog
53
ChangeLog
@@ -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
|
||||
|
||||
|
||||
32
Makefile
32
Makefile
@@ -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 $@ $<
|
||||
|
||||
22
README.txt
22
README.txt
@@ -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
18
Todo
@@ -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
156
audio.c
@@ -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
13
audio.h
@@ -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
80
codec.c
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
492
softhddev.c
492
softhddev.c
@@ -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");
|
||||
|
||||
217
softhddevice.cpp
217
softhddevice.cpp
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
6
video.h
6
video.h
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user