mirror of
https://projects.vdr-developer.org/git/vdr-plugin-softhddevice.git
synced 2023-10-10 17:16:51 +00:00
Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
00cafd18ed | ||
|
|
ab4e89132e | ||
|
|
3585f1df19 | ||
|
|
e258c35537 | ||
|
|
91dbe46786 | ||
|
|
a7389111ff | ||
|
|
27e9a88e2f | ||
|
|
33e9c71aea | ||
|
|
bd84e3f3b9 | ||
|
|
364cc04736 | ||
| ec4a899bb8 | |||
|
|
dab31e2367 | ||
|
|
e613ff1f7e | ||
|
|
1886b745e5 | ||
|
|
422c378a5e |
76
ChangeLog
76
ChangeLog
@@ -1,5 +1,79 @@
|
||||
User johns
|
||||
Date:
|
||||
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
|
||||
|
||||
Release Version 0.4.6
|
||||
Warn only on the first duplicated frame in sequence.
|
||||
Increase audio buffer, if bigger audio delay is used.
|
||||
Makes SkipLines configure in setup menu.
|
||||
Auto-crop only enabled with normal 4:3 display mode.
|
||||
Vaapi updates OSD when cropping changes.
|
||||
Add A-V info output and compile time option.
|
||||
Fix bug: VA-API intel software decoder broken by aspect commit.
|
||||
Add support for 4:3 output modes.
|
||||
Quicker auto-crop after channel switch.
|
||||
Add auto-crop support for Intel VA-API backend.
|
||||
Fix bug: Auto-Crop logo skip didn't use displayed width.
|
||||
Workaround for mpeg2 FFMpeg + VA-API + Intel GPU hung.
|
||||
Fix bug: Missing vaSyncSurface and vaDestroyImage.
|
||||
Fix bug: Only black picture with VA-API hw decoder.
|
||||
|
||||
User HelAu
|
||||
Date: Mon Jan 30 16:54:47 CET 2012
|
||||
|
||||
Add support to start the plugin in suspended mode.
|
||||
|
||||
User johns
|
||||
Date: Mon Jan 30 15:58:21 CET 2012
|
||||
|
||||
Finished rewrite of video code, to support output modules.
|
||||
Add aspect change support to software decoder path.
|
||||
Repair software decoder with vaapi vdpau backend.
|
||||
Add workaround for Intel VA-API MPEG GPU hung.
|
||||
|
||||
User johns
|
||||
Date: Sat Jan 28 13:32:12 CET 2012
|
||||
|
||||
Release Version 0.4.5
|
||||
Add configurable skip lines at video top and bottom.
|
||||
|
||||
33
Makefile
33
Makefile
@@ -19,19 +19,20 @@ GIT_REV = $(shell git describe --always 2>/dev/null)
|
||||
### Configuration (edit this for your needs)
|
||||
|
||||
CONFIG := #-DDEBUG
|
||||
CONFIG += -DAV_INFO
|
||||
#CONFIG += -DHAVE_PTHREAD_NAME
|
||||
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:
|
||||
@@ -70,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) \
|
||||
@@ -86,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):
|
||||
|
||||
@@ -121,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 $@ $<
|
||||
|
||||
21
README.txt
21
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
|
||||
|
||||
@@ -146,6 +154,12 @@ Setup: /etc/vdr/setup.conf
|
||||
if detected crop area is too small, cut max 'n' pixels at top and
|
||||
bottom.
|
||||
|
||||
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.
|
||||
@@ -154,6 +168,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
|
||||
------
|
||||
|
||||
|
||||
37
Todo
37
Todo
@@ -21,11 +21,11 @@ $Id: $
|
||||
missing:
|
||||
software deinterlace (yadif, ...)
|
||||
software decoder with software deinterlace
|
||||
zoom/fit-zoom 4:3 (SetVideoDisplayFormat, SetVideoFormat?)
|
||||
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!
|
||||
Make output drivers better modular (under construction).
|
||||
ColorSpace aren't configurable with the gui.
|
||||
Inverse telecine isn't configurable with the gui.
|
||||
|
||||
crash:
|
||||
AudioPlayHandlerThread -> pthread_cond_wait
|
||||
@@ -35,18 +35,20 @@ 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 line 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
|
||||
|
||||
libva:
|
||||
yaepghd (VaapiSetOutputPosition) support
|
||||
can associate only displayed part of osd
|
||||
grab image for va-api
|
||||
still many:
|
||||
remove stderr output of libva init
|
||||
still many: (workaround export NO_MPEG_HW=1)
|
||||
[drm:i915_hangcheck_elapsed] *ERROR* Hangcheck timer elapsed... GPU hung
|
||||
[drm:i915_wait_request] *ERROR* i915_wait_request returns -11 ...
|
||||
|
||||
@@ -54,28 +56,33 @@ libva: branch vaapi-ext
|
||||
add support for vaapi-ext
|
||||
|
||||
libva-intel-driver:
|
||||
deinterlace only supported with vaapi-ext
|
||||
1080i does no v-sync (sometimes correct working with vaapi-ext)
|
||||
OSD has sometimes wrong size (workaround written)
|
||||
software decoder needs UV swab
|
||||
sometimes software decoder deinterlace isn't working and 1080i channels
|
||||
show artefacts
|
||||
|
||||
libva-vdpau-driver:
|
||||
G210/GT520 OSD update too slow (needs hardware problem workaround)
|
||||
hangup on exit (VaapiDelDecoder -> VaapiCleanup
|
||||
-> vaDestroyContext -> pthread_rwlock_wrlock)
|
||||
with auto-crop OSD has wrong position
|
||||
OSD still has some problems with auto-crop and 4:3 zoom.
|
||||
|
||||
libva-xvba-driver:
|
||||
with auto-crop OSD has wrong position
|
||||
|
||||
x11:
|
||||
disable screensaver
|
||||
skip multiple configure-notify, handle only the last one.
|
||||
support embedded mode
|
||||
|
||||
audio:
|
||||
write TS -> PES parser, which feeds audio before the next start packet
|
||||
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
|
||||
@@ -85,12 +92,11 @@ audio/alsa:
|
||||
|
||||
audio/oss:
|
||||
alsa oss emulation mixer "pcm" not working
|
||||
oss4 mixer channel not working
|
||||
ring buffer overflow with alsa oss emulation
|
||||
|
||||
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
|
||||
@@ -105,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)
|
||||
@@ -118,5 +122,6 @@ future features (not planed for 1.0 - 1.5)
|
||||
atmolight support
|
||||
multistream handling
|
||||
pip support
|
||||
save and use auto-crop with channel zapping
|
||||
|
||||
upmix stereo to AC-3
|
||||
upmix stereo to AC-3 (supported by alsa plugin)
|
||||
|
||||
158
audio.c
158
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,12 +136,12 @@ 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
|
||||
static int64_t AudioPTS; ///< audio pts clock
|
||||
static const int AudioBufferTime = 450; ///< audio buffer time in ms
|
||||
static const int AudioBufferTime = 350; ///< audio buffer time in ms
|
||||
|
||||
#ifdef USE_AUDIO_THREAD
|
||||
static pthread_t AudioThread; ///< audio play thread
|
||||
@@ -147,6 +151,8 @@ static pthread_cond_t AudioStartCond; ///< condition variable
|
||||
static const int AudioThread; ///< dummy audio thread
|
||||
#endif
|
||||
|
||||
extern int VideoAudioDelay; /// import audio/video delay
|
||||
|
||||
#ifdef USE_AUDIORING
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -332,7 +338,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);
|
||||
}
|
||||
}
|
||||
@@ -561,7 +569,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
|
||||
@@ -620,6 +627,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"));
|
||||
@@ -631,7 +641,7 @@ static void AlsaThread(void)
|
||||
usleep(100 * 1000);
|
||||
continue;
|
||||
}
|
||||
if (AlsaFlushBuffer) {
|
||||
if (AlsaFlushBuffer || AudioPaused) {
|
||||
continue;
|
||||
}
|
||||
if ((err = AlsaPlayRingbuffer())) { // empty / error
|
||||
@@ -816,7 +826,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 =
|
||||
@@ -900,6 +910,7 @@ static int AlsaSetup(int *freq, int *channels, int use_ac3)
|
||||
snd_pcm_uframes_t period_size;
|
||||
int err;
|
||||
int ret;
|
||||
int delay;
|
||||
snd_pcm_t *handle;
|
||||
|
||||
if (!AlsaPCMHandle) { // alsa not running yet
|
||||
@@ -1085,11 +1096,14 @@ static int AlsaSetup(int *freq, int *channels, int use_ac3)
|
||||
|
||||
AlsaStartThreshold = snd_pcm_frames_to_bytes(AlsaPCMHandle, period_size);
|
||||
// buffer time/delay in ms
|
||||
delay = AudioBufferTime;
|
||||
if (VideoAudioDelay > -100) {
|
||||
delay += 100 + VideoAudioDelay / 90;
|
||||
}
|
||||
if (AlsaStartThreshold <
|
||||
(*freq * *channels * AudioBytesProSample * AudioBufferTime) / 1000U) {
|
||||
(*freq * *channels * AudioBytesProSample * delay) / 1000U) {
|
||||
AlsaStartThreshold =
|
||||
(*freq * *channels * AudioBytesProSample * AudioBufferTime) /
|
||||
1000U;
|
||||
(*freq * *channels * AudioBytesProSample * delay) / 1000U;
|
||||
}
|
||||
// no bigger, than the buffer
|
||||
if (AlsaStartThreshold > RingBufferFreeBytes(AlsaRingBuffer)) {
|
||||
@@ -1101,6 +1115,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
|
||||
*/
|
||||
@@ -1169,6 +1224,8 @@ static const AudioModule AlsaModule = {
|
||||
.GetDelay = AlsaGetDelay,
|
||||
.SetVolume = AlsaSetVolume,
|
||||
.Setup = AlsaSetup,
|
||||
.Play = AlsaPlay,
|
||||
.Pause = AlsaPause,
|
||||
.Init = AlsaInit,
|
||||
.Exit = AlsaExit,
|
||||
};
|
||||
@@ -1378,6 +1435,9 @@ static void OssThread(void)
|
||||
OssFlushBuffer = 0;
|
||||
break;
|
||||
}
|
||||
if (AudioPaused) {
|
||||
break;
|
||||
}
|
||||
|
||||
fds[0].fd = OssPcmFildes;
|
||||
fds[0].events = POLLOUT | POLLERR;
|
||||
@@ -1389,7 +1449,7 @@ static void OssThread(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (OssFlushBuffer) {
|
||||
if (OssFlushBuffer || AudioPaused) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1622,6 +1682,7 @@ static int OssSetup(int *freq, int *channels, int use_ac3)
|
||||
{
|
||||
int ret;
|
||||
int tmp;
|
||||
int delay;
|
||||
|
||||
if (OssPcmFildes == -1) { // OSS not ready
|
||||
return -1;
|
||||
@@ -1708,12 +1769,14 @@ static int OssSetup(int *freq, int *channels, int use_ac3)
|
||||
// start when enough bytes for initial write
|
||||
OssStartThreshold = bi.bytes + tmp;
|
||||
// buffer time/delay in ms
|
||||
delay = AudioBufferTime;
|
||||
if (VideoAudioDelay > -100) {
|
||||
delay += 100 + VideoAudioDelay / 90;
|
||||
}
|
||||
if (OssStartThreshold <
|
||||
(*freq * *channels * AudioBytesProSample * AudioBufferTime) /
|
||||
1000U) {
|
||||
(*freq * *channels * AudioBytesProSample * delay) / 1000U) {
|
||||
OssStartThreshold =
|
||||
(*freq * *channels * AudioBytesProSample * AudioBufferTime) /
|
||||
1000U;
|
||||
(*freq * *channels * AudioBytesProSample * delay) / 1000U;
|
||||
}
|
||||
// no bigger, than the buffer
|
||||
if (OssStartThreshold > RingBufferFreeBytes(OssRingBuffer)) {
|
||||
@@ -1727,6 +1790,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.
|
||||
*/
|
||||
@@ -1772,6 +1849,8 @@ static const AudioModule OssModule = {
|
||||
.GetDelay = OssGetDelay,
|
||||
.SetVolume = OssSetVolume,
|
||||
.Setup = OssSetup,
|
||||
.Play = OssPlay,
|
||||
.Pause = OssPause,
|
||||
.Init = OssInit,
|
||||
.Exit = OssExit,
|
||||
};
|
||||
@@ -1855,6 +1934,8 @@ static const AudioModule NoopModule = {
|
||||
.GetDelay = NoopGetDelay,
|
||||
.SetVolume = NoopSetVolume,
|
||||
.Setup = NoopSetup,
|
||||
.Play = NoopVoid,
|
||||
.Pause = NoopVoid,
|
||||
.Init = NoopVoid,
|
||||
.Exit = NoopVoid,
|
||||
};
|
||||
@@ -2057,13 +2138,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2097,6 +2172,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.
|
||||
**
|
||||
@@ -2137,6 +2238,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.
|
||||
**
|
||||
@@ -2188,8 +2301,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);
|
||||
}
|
||||
}
|
||||
|
||||
456
softhddev.c
456
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"
|
||||
@@ -61,10 +58,12 @@ static char ConfigVdpauDecoder = 1; ///< use vdpau decoder, if possible
|
||||
#endif
|
||||
|
||||
static char ConfigFullscreen; ///< fullscreen modus
|
||||
static char ConfigStartSuspended; ///< flag to start in suspend mode
|
||||
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,6 +73,7 @@ static volatile char NewAudioStream; ///< new audio stream
|
||||
static volatile char SkipAudio; ///< skip audio stream
|
||||
static AudioDecoder *MyAudioDecoder; ///< audio decoder
|
||||
static enum CodecID AudioCodecID; ///< current codec id
|
||||
static int AudioChannelID; ///< current audio channel id
|
||||
|
||||
/**
|
||||
** mpeg bitrate table.
|
||||
@@ -200,8 +200,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;
|
||||
@@ -209,7 +208,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
|
||||
@@ -259,64 +258,127 @@ 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;
|
||||
}
|
||||
// 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) {
|
||||
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 + 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) {
|
||||
Debug(3, "[softhddev]%s: ??? %d\n", __FUNCTION__, id);
|
||||
avpkt->data = (void *)data;
|
||||
avpkt->size = size;
|
||||
n = FindAudioSync(avpkt);
|
||||
if (n < 0) {
|
||||
return osize;
|
||||
}
|
||||
|
||||
avpkt->pts = AV_NOPTS_VALUE;
|
||||
CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_MP2);
|
||||
AudioCodecID = CODEC_ID_MP2;
|
||||
data += n;
|
||||
size -= n;
|
||||
}
|
||||
}
|
||||
// no decoder or codec known
|
||||
// still no decoder or codec known
|
||||
if (AudioCodecID == CODEC_ID_NONE) {
|
||||
return osize;
|
||||
}
|
||||
}
|
||||
|
||||
avpkt->data = (void *)data;
|
||||
avpkt->size = size;
|
||||
//memset(avpkt->data + avpkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
|
||||
CodecAudioDecode(MyAudioDecoder, avpkt);
|
||||
if (AudioCodecID == CODEC_ID_PCM_DVD) {
|
||||
if (size > 7) {
|
||||
char *buf;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -421,6 +483,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,
|
||||
@@ -485,6 +548,50 @@ static void VideoNextPacket(int codec_id)
|
||||
avpkt->dts = AV_NOPTS_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
** Fix packet for FFMpeg.
|
||||
**
|
||||
** Some tv-stations sends mulitple pictures in a singe PES packet.
|
||||
** Current ffmpeg 0.10 and libav-0.8 has problems with this.
|
||||
** Split the packet into single picture packets.
|
||||
*/
|
||||
void FixPacketForFFMpeg(VideoDecoder * MyVideoDecoder, AVPacket * avpkt)
|
||||
{
|
||||
uint8_t *p;
|
||||
int n;
|
||||
AVPacket tmp[1];
|
||||
int first;
|
||||
|
||||
p = avpkt->data;
|
||||
n = avpkt->size;
|
||||
*tmp = *avpkt;
|
||||
|
||||
first = 1;
|
||||
while (n > 4) {
|
||||
// scan for picture header 0x00000100
|
||||
if (!p[0] && !p[1] && p[2] == 0x01 && !p[3]) {
|
||||
if (first) {
|
||||
first = 0;
|
||||
n -= 4;
|
||||
p += 4;
|
||||
continue;
|
||||
}
|
||||
// packet has already an picture header
|
||||
tmp->size = p - tmp->data;
|
||||
CodecVideoDecode(MyVideoDecoder, tmp);
|
||||
// time-stamp only valid for first packet
|
||||
tmp->pts = AV_NOPTS_VALUE;
|
||||
tmp->dts = AV_NOPTS_VALUE;
|
||||
tmp->data = p;
|
||||
tmp->size = n;
|
||||
}
|
||||
--n;
|
||||
++p;
|
||||
}
|
||||
|
||||
CodecVideoDecode(MyVideoDecoder, tmp);
|
||||
}
|
||||
|
||||
/**
|
||||
** Decode from PES packet ringbuffer.
|
||||
*/
|
||||
@@ -495,7 +602,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) {
|
||||
@@ -559,7 +666,33 @@ int VideoDecode(void)
|
||||
avpkt->size = avpkt->stream_index;
|
||||
avpkt->stream_index = 0;
|
||||
|
||||
CodecVideoDecode(MyVideoDecoder, avpkt);
|
||||
if (0) {
|
||||
static int done;
|
||||
|
||||
if (done < 2) {
|
||||
int fildes;
|
||||
int who_designed_this_is____;
|
||||
|
||||
if (done == 0)
|
||||
fildes =
|
||||
open("frame0.pes", O_WRONLY | O_TRUNC | O_CREAT, 0666);
|
||||
else if (done == 1)
|
||||
fildes =
|
||||
open("frame1.pes", O_WRONLY | O_TRUNC | O_CREAT, 0666);
|
||||
else
|
||||
fildes =
|
||||
open("frame2.pes", O_WRONLY | O_TRUNC | O_CREAT, 0666);
|
||||
done++;
|
||||
who_designed_this_is____ = write(fildes, avpkt->data, avpkt->size);
|
||||
close(fildes);
|
||||
}
|
||||
}
|
||||
|
||||
if (last_codec_id == CODEC_ID_MPEG2VIDEO) {
|
||||
FixPacketForFFMpeg(MyVideoDecoder, avpkt);
|
||||
} else {
|
||||
CodecVideoDecode(MyVideoDecoder, avpkt);
|
||||
}
|
||||
|
||||
avpkt->size = saved_size;
|
||||
|
||||
@@ -674,6 +807,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;
|
||||
@@ -685,7 +820,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
|
||||
@@ -748,9 +883,72 @@ 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) {
|
||||
Error(_("[softhddev] invalid 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 - 5, l + 5);
|
||||
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 - 3, l + 3);
|
||||
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;
|
||||
}
|
||||
|
||||
return size;
|
||||
#else
|
||||
// FIXME: no valid mpeg2/h264 detection yet
|
||||
// FIXME: better skip all zero's >3 && 0x01 0x09 h264, >2 && 0x01 -> mpeg2
|
||||
|
||||
@@ -809,10 +1007,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)
|
||||
{
|
||||
@@ -865,21 +1079,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"));
|
||||
@@ -894,6 +1102,10 @@ uint8_t *GrabImage(int *size, int jpeg, int quality, int width, int height)
|
||||
*/
|
||||
void SetPlayMode(void)
|
||||
{
|
||||
if (ConfigStartSuspended) { // ignore first call, if start suspended
|
||||
ConfigStartSuspended = 0;
|
||||
return;
|
||||
}
|
||||
Resume();
|
||||
if (MyVideoDecoder) {
|
||||
if (VideoCodecID != CODEC_ID_NONE) {
|
||||
@@ -906,9 +1118,7 @@ void SetPlayMode(void)
|
||||
NewAudioStream = 1;
|
||||
}
|
||||
}
|
||||
VideoFreezed = 0;
|
||||
SkipAudio = 0;
|
||||
SkipVideo = 0;
|
||||
StreamFreezed = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -933,9 +1143,9 @@ void Clear(void)
|
||||
*/
|
||||
void Play(void)
|
||||
{
|
||||
VideoFreezed = 0;
|
||||
StreamFreezed = 0;
|
||||
SkipAudio = 0;
|
||||
// FIXME: restart audio
|
||||
AudioPlay();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -943,13 +1153,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)
|
||||
{
|
||||
@@ -962,10 +1174,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
|
||||
|
||||
@@ -975,28 +1187,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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1079,19 +1305,22 @@ void OsdDrawARGB(int x, int y, int height, int width, const uint8_t * argb)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static char ConfigStartX11Server; ///< flag start the x11 server
|
||||
|
||||
/**
|
||||
** Return command line help string.
|
||||
*/
|
||||
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";
|
||||
" -x\t\tstart x11 server\n" " -s\t\tstart in suspended mode\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";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1106,10 +1335,13 @@ int ProcessArgs(int argc, char *const argv[])
|
||||
// Parse arguments.
|
||||
//
|
||||
for (;;) {
|
||||
switch (getopt(argc, argv, "-a:p:d:fg:x")) {
|
||||
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;
|
||||
@@ -1130,6 +1362,20 @@ int ProcessArgs(int argc, char *const argv[])
|
||||
case 'x': // x11 server
|
||||
ConfigStartX11Server = 1;
|
||||
continue;
|
||||
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 '-':
|
||||
@@ -1261,7 +1507,7 @@ void SoftHdDeviceExit(void)
|
||||
StopVideo();
|
||||
|
||||
CodecExit();
|
||||
VideoPacketExit();
|
||||
//VideoPacketExit();
|
||||
|
||||
if (ConfigStartX11Server) {
|
||||
Debug(3, "x-setup: Stop x11 server\n");
|
||||
@@ -1311,15 +1557,19 @@ void Start(void)
|
||||
}
|
||||
CodecInit();
|
||||
|
||||
// FIXME: AudioInit for HDMI after X11 startup
|
||||
AudioInit();
|
||||
MyAudioDecoder = CodecAudioNewDecoder();
|
||||
AudioCodecID = CODEC_ID_NONE;
|
||||
if (!ConfigStartSuspended) {
|
||||
// FIXME: AudioInit for HDMI after X11 startup
|
||||
AudioInit();
|
||||
MyAudioDecoder = CodecAudioNewDecoder();
|
||||
AudioCodecID = CODEC_ID_NONE;
|
||||
|
||||
if (!ConfigStartX11Server) {
|
||||
StartVideo();
|
||||
if (!ConfigStartX11Server) {
|
||||
StartVideo();
|
||||
}
|
||||
} else {
|
||||
SkipVideo = 1;
|
||||
SkipAudio = 1;
|
||||
}
|
||||
|
||||
pthread_mutex_init(&SuspendLockMutex, NULL);
|
||||
}
|
||||
|
||||
|
||||
253
softhddevice.cpp
253
softhddevice.cpp
@@ -42,7 +42,7 @@ extern "C"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static const char *const VERSION = "0.4.5";
|
||||
static const char *const VERSION = "0.4.7";
|
||||
static const char *const DESCRIPTION =
|
||||
trNOOP("A software and GPU emulated HD device");
|
||||
|
||||
@@ -61,6 +61,9 @@ static const char *const Resolution[RESOLUTIONS] = {
|
||||
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];
|
||||
|
||||
@@ -77,7 +80,6 @@ static int ConfigVideoSharpen[RESOLUTIONS];
|
||||
static int ConfigVideoScaling[RESOLUTIONS];
|
||||
|
||||
static int ConfigVideoAudioDelay; ///< config audio delay
|
||||
static int ConfigVideoSkipLines; ///< config skip lines top/bottom
|
||||
static int ConfigAudioPassthrough; ///< config audio pass-through
|
||||
|
||||
static int ConfigAutoCropInterval; ///< auto crop detection interval
|
||||
@@ -147,9 +149,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)
|
||||
{
|
||||
@@ -166,6 +193,7 @@ cSoftOsd::~cSoftOsd(void)
|
||||
{
|
||||
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
||||
SetActive(false);
|
||||
// done by SetActive: OsdClose();
|
||||
|
||||
#ifdef USE_YAEPG
|
||||
// support yaepghd, video window
|
||||
@@ -179,12 +207,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;
|
||||
@@ -227,43 +254,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"));
|
||||
@@ -277,14 +293,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;
|
||||
}
|
||||
|
||||
@@ -329,6 +345,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)
|
||||
{
|
||||
@@ -364,6 +384,8 @@ class cMenuSetupSoft:public cMenuSetupPage
|
||||
protected:
|
||||
int MakePrimary;
|
||||
int HideMainMenuEntry;
|
||||
int SkipLines;
|
||||
int StudioLevels;
|
||||
int Scaling[RESOLUTIONS];
|
||||
int Deinterlace[RESOLUTIONS];
|
||||
int SkipChromaDeinterlace[RESOLUTIONS];
|
||||
@@ -403,7 +425,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"
|
||||
@@ -428,12 +451,20 @@ cMenuSetupSoft::cMenuSetupSoft(void)
|
||||
// video
|
||||
//
|
||||
Add(SeparatorItem(tr("Video")));
|
||||
|
||||
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)"),
|
||||
@@ -491,6 +522,11 @@ void cMenuSetupSoft::Store(void)
|
||||
SetupStore("HideMainMenuEntry", ConfigHideMainMenuEntry =
|
||||
HideMainMenuEntry);
|
||||
|
||||
SetupStore("SkipLines", ConfigVideoSkipLines = SkipLines);
|
||||
VideoSetSkipLines(ConfigVideoSkipLines);
|
||||
SetupStore("StudioLevels", ConfigVideoStudioLevels = StudioLevels);
|
||||
VideoSetStudioLevels(ConfigVideoStudioLevels);
|
||||
|
||||
for (i = 0; i < RESOLUTIONS; ++i) {
|
||||
char buf[128];
|
||||
|
||||
@@ -520,8 +556,10 @@ void cMenuSetupSoft::Store(void)
|
||||
|
||||
SetupStore("AutoCrop.Interval", ConfigAutoCropInterval = AutoCropInterval);
|
||||
SetupStore("AutoCrop.Delay", ConfigAutoCropDelay = AutoCropDelay);
|
||||
SetupStore("AutoCrop.Tolerance", ConfigAutoCropTolerance = AutoCropTolerance);
|
||||
VideoSetAutoCrop(ConfigAutoCropInterval, ConfigAutoCropDelay, ConfigAutoCropTolerance);
|
||||
SetupStore("AutoCrop.Tolerance", ConfigAutoCropTolerance =
|
||||
AutoCropTolerance);
|
||||
VideoSetAutoCrop(ConfigAutoCropInterval, ConfigAutoCropDelay,
|
||||
ConfigAutoCropTolerance);
|
||||
|
||||
SetupStore("Suspend.Close", ConfigSuspendClose = SuspendClose);
|
||||
SetupStore("Suspend.X11", ConfigSuspendX11 = SuspendX11);
|
||||
@@ -560,9 +598,8 @@ cSoftHdPlayer::~cSoftHdPlayer()
|
||||
*/
|
||||
class cSoftHdControl:public cControl
|
||||
{
|
||||
private:
|
||||
cSoftHdPlayer * Player;
|
||||
public:
|
||||
static cSoftHdPlayer *Player; ///< dummy player
|
||||
virtual void Hide(void)
|
||||
{
|
||||
}
|
||||
@@ -573,6 +610,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) {
|
||||
@@ -580,8 +624,8 @@ eOSState cSoftHdControl::ProcessKey(eKeys key)
|
||||
delete Player;
|
||||
|
||||
Player = NULL;
|
||||
Resume();
|
||||
}
|
||||
Resume();
|
||||
return osEnd;
|
||||
}
|
||||
return osContinue;
|
||||
@@ -620,11 +664,11 @@ 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);
|
||||
virtual int64_t GetSTC(void);
|
||||
virtual void SetVideoDisplayFormat(eVideoDisplayFormat);
|
||||
virtual void GetVideoSize(int &, int &, double &);
|
||||
virtual void GetOsdSize(int &, int &, double &);
|
||||
virtual int PlayVideo(const uchar *, int);
|
||||
@@ -637,6 +681,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
|
||||
@@ -662,6 +707,7 @@ cSoftHdDevice::cSoftHdDevice(void)
|
||||
#if 0
|
||||
spuDecoder = NULL;
|
||||
#endif
|
||||
SetVideoDisplayFormat(eVideoDisplayFormat(Setup.VideoDisplayFormat));
|
||||
}
|
||||
|
||||
cSoftHdDevice::~cSoftHdDevice(void)
|
||||
@@ -740,6 +786,10 @@ bool cSoftHdDevice::SetPlayMode(ePlayMode play_mode)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
** Gets the current System Time Counter, which can be used to
|
||||
** synchronize audio, video and subtitles.
|
||||
*/
|
||||
int64_t cSoftHdDevice::GetSTC(void)
|
||||
{
|
||||
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
||||
@@ -784,6 +834,9 @@ void cSoftHdDevice::Freeze(void)
|
||||
::Freeze();
|
||||
}
|
||||
|
||||
/**
|
||||
** Turns off audio while replaying.
|
||||
*/
|
||||
void cSoftHdDevice::Mute(void)
|
||||
{
|
||||
dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
||||
@@ -792,13 +845,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.
|
||||
*/
|
||||
@@ -843,6 +889,30 @@ 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 this function isn't called on the initial channel
|
||||
*/
|
||||
void cSoftHdDevice::SetVideoDisplayFormat(
|
||||
eVideoDisplayFormat video_display_format)
|
||||
{
|
||||
static int last = -1;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** Returns the width, height and video_aspect ratio of the currently
|
||||
** displayed video material.
|
||||
@@ -899,11 +969,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);
|
||||
@@ -958,6 +1040,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
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@@ -1103,12 +1195,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;
|
||||
@@ -1168,6 +1262,14 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
|
||||
ConfigHideMainMenuEntry = atoi(value);
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(name, "SkipLines")) {
|
||||
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];
|
||||
|
||||
@@ -1204,10 +1306,6 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
|
||||
}
|
||||
}
|
||||
|
||||
if (!strcmp(name, "SkipLines")) {
|
||||
VideoSetSkipLines(ConfigVideoSkipLines = atoi(value));
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(name, "AudioDelay")) {
|
||||
VideoSetAudioDelay(ConfigVideoAudioDelay = atoi(value));
|
||||
return true;
|
||||
@@ -1228,7 +1326,8 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(name, "AutoCrop.Tolerance")) {
|
||||
VideoSetAutoCrop(ConfigAutoCropInterval, ConfigAutoCropDelay, ConfigAutoCropTolerance = atoi(value));
|
||||
VideoSetAutoCrop(ConfigAutoCropInterval, ConfigAutoCropDelay,
|
||||
ConfigAutoCropTolerance = atoi(value));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1268,10 +1367,8 @@ const char **cPluginSoftHdDevice::SVDRPHelpPages(void)
|
||||
{
|
||||
// FIXME: translation?
|
||||
static const char *text[] = {
|
||||
"SUSP\n"
|
||||
" Suspend plugin.\n",
|
||||
"RESU\n"
|
||||
" Resume plugin.\n",
|
||||
"SUSP\n" " Suspend plugin.\n",
|
||||
"RESU\n" " Resume plugin.\n",
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -1286,6 +1383,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);
|
||||
@@ -1295,8 +1396,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
|
||||
|
||||
19
video.h
19
video.h
@@ -47,16 +47,17 @@ extern unsigned VideoGetSurface(VideoHwDecoder *);
|
||||
extern void VideoReleaseSurface(VideoHwDecoder *, unsigned);
|
||||
|
||||
#ifdef LIBAVCODEC_VERSION
|
||||
/// Render a ffmpeg frame.
|
||||
extern void VideoRenderFrame(VideoHwDecoder *, AVCodecContext *, AVFrame *);
|
||||
|
||||
/// Get ffmpeg vaapi context.
|
||||
extern struct vaapi_context *VideoGetVaapiContext(VideoHwDecoder *);
|
||||
|
||||
/// Callback to negotiate the PixelFormat.
|
||||
extern enum PixelFormat Video_get_format(VideoHwDecoder *, AVCodecContext *,
|
||||
const enum PixelFormat *);
|
||||
|
||||
/// Render a ffmpeg frame.
|
||||
extern void VideoRenderFrame(VideoHwDecoder *, const AVCodecContext *,
|
||||
const AVFrame *);
|
||||
|
||||
/// Get ffmpeg vaapi context.
|
||||
extern struct vaapi_context *VideoGetVaapiContext(VideoHwDecoder *);
|
||||
|
||||
#ifdef AVCODEC_VDPAU_H
|
||||
/// Draw vdpau render state.
|
||||
extern void VideoDrawRenderState(VideoHwDecoder *,
|
||||
@@ -79,6 +80,9 @@ extern void VideoSetOutputPosition(int, int, int, int);
|
||||
/// Set video mode.
|
||||
extern void VideoSetVideoMode(int, int, int, int);
|
||||
|
||||
/// Set display format.
|
||||
extern void VideoSetDisplayFormat(int);
|
||||
|
||||
/// Set video fullscreen mode.
|
||||
extern void VideoSetFullscreen(int);
|
||||
|
||||
@@ -100,6 +104,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