19 Commits
0.3.0 ... 0.3.1

Author SHA1 Message Date
Johns
e619f5c836 Release Version 0.3.1. 2012-01-15 16:57:03 +01:00
Johns
973fcfe4dd Support BBC-HD (no clean solution). 2012-01-15 14:31:54 +01:00
Johns
eec30433b6 Fix bug: AudioFreeBytes fails if no audio ready. 2012-01-13 22:39:04 +01:00
Johns
baf577aba5 Fix bug: snd_pcm_state: Assertion `pcm' failed. 2012-01-13 19:33:59 +01:00
Johns
81d7ef9755 Support xcb_ewmh.h for xcb-util <0.3.8. 2012-01-13 17:20:43 +01:00
Johns
7f7de8678f Add support for fullscreen mode. 2012-01-13 16:31:29 +01:00
Johns
92bb00c410 Add vaapi color space conversion. 2012-01-13 12:28:56 +01:00
Johns
d3b98b90f4 Fix bug: devision by zero in ...UpdateOutput, 2012-01-13 10:04:26 +01:00
Johns
788636ee6b Destroy vdpau surface only, when initialized. 2012-01-13 00:58:30 +01:00
Johns
8e53cbd4a9 VAAPI: Instant use new deinterlace configuration. 2012-01-12 23:07:06 +01:00
Johns
54661f90ea Weave is deinterlace disabled. 2012-01-12 20:54:49 +01:00
Johns
30d8e8afe9 Fix subtitle position. 2012-01-12 18:55:07 +01:00
Johns
19a37bb0bf Add SVDRP support. 2012-01-12 15:20:01 +01:00
Johns
2087968d55 Rebuild objects, when Makefile changes. 2012-01-12 15:19:19 +01:00
Johns
d983f780b3 Suspend when user is inactive. 2012-01-11 18:01:18 +01:00
712b2e0de1 Patch collection from Christian Ruppert.
Move objects before $LIBS to avoid link failures with --as-needed.
Do not override CFLAGS for video test.
Rearrange *FLAGS incl. some minor fixes.
Don't override VDRDIR, LIBDIR and TMPDIR in makefile.
Don't abuse LDFLAGS in makefile.
Define CC in makefile.
Include GL/gl.h for the GL_COLOR_BUFFER_BIT definition.
VideoInit() needs an argument.
2012-01-10 22:48:42 +01:00
Johns
54f92e67fc Don't mute hardware while replaying. 2012-01-10 16:41:46 +01:00
Johns
960cd27ab5 Add support for close and resize x11 window. 2012-01-10 15:53:54 +01:00
Johns
3a97700981 Add main menu entry, which suspends the plugin. 2012-01-10 15:52:07 +01:00
10 changed files with 727 additions and 264 deletions

View File

@@ -1,4 +1,34 @@
User johns
Date: Sun Jan 15 16:56:04 CET 2012
Release Version 0.3.1
Fix bug: AudioFreeBytes didn't check if audio running/compiled.
Fix bug: snd_pcm_state: Assertion `pcm' failed.
Add support for fullscreen and fullscreen toogle.
Instant update deinterlace configuration changes.
Fix subtitle position.
Add SVDRP support.
Suspend when user is inactive.
User Christian Rupper
Date: Tue Jan 10 22:33:14 CET 2012
Move objects before $LIBS to avoid link failures with --as-needed.
Do not override CFLAGS for video test.
Rearrange *FLAGS incl. some minor fixes.
Don't override VDRDIR, LIBDIR and TMPDIR in makefile.
Don't abuse LDFLAGS in makefile.
Define CC in makefile.
Include GL/gl.h for the GL_COLOR_BUFFER_BIT definition.
VideoInit() needs an argument.
User johns
Date: Tue Jan 10 22:32:50 CET 2012
Add main menu entry, which suspends the plugin.
Add support for resize window.
Close window sends "close" as remote key press.
Date: Mon Jan 9 22:09:38 CET 2012
Release Version 0.3.0

View File

@@ -26,40 +26,17 @@ CONFIG += $(shell pkg-config --exists alsa && echo "-DUSE_ALSA")
### The C++ compiler and options:
CC ?= gcc
CXX ?= g++
CXXFLAGS ?= -g -O2 -W -Wall -Wextra -Woverloaded-virtual -fPIC
override CXXFLAGS += $(DEFINES) $(INCLUDES)
CFLAGS ?= -g -O2 -W -Wall -Wextra -Winit-self \
-Wdeclaration-after-statement -fPIC
#CFLAGS += -Werror
override CFLAGS += $(DEFINES) $(INCLUDES) \
$(shell pkg-config --cflags libavcodec libavformat) \
`pkg-config --cflags x11 x11-xcb xcb xcb-xv xcb-shm xcb-dpms xcb-atom\
xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\
`pkg-config --cflags gl glu` \
$(if $(findstring USE_VDPAU,$(CONFIG)), \
`pkg-config --cflags vdpau`) \
$(if $(findstring USE_VAAPI,$(CONFIG)), \
`pkg-config --cflags libva-x11 libva-glx libva`) \
$(if $(findstring USE_ALSA,$(CONFIG)), \
`pkg-config --cflags alsa`)
override LDFLAGS += -lrt \
$(shell pkg-config --libs libavcodec libavformat) \
`pkg-config --libs x11 x11-xcb xcb xcb-xv xcb-shm xcb-dpms xcb-atom\
xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\
`pkg-config --libs gl glu` \
$(if $(findstring USE_VDPAU,$(CONFIG)), \
`pkg-config --libs vdpau`) \
$(if $(findstring USE_VAAPI,$(CONFIG)), \
`pkg-config --libs libva-x11 libva-glx libva`) \
$(if $(findstring USE_ALSA,$(CONFIG)), \
`pkg-config --libs alsa`)
-Wdeclaration-after-statement
CXXFLAGS ?= -g -O2 -W -Wall -Wextra -Woverloaded-virtual
### The directory environment:
VDRDIR = ../../..
LIBDIR = ../../lib
TMPDIR = /tmp
VDRDIR ?= ../../..
LIBDIR ?= ../../lib
TMPDIR ?= /tmp
### Make sure that necessary options are included:
@@ -78,12 +55,40 @@ APIVERSION = $(shell sed -ne '/define APIVERSION/s/^.*"\(.*\)".*$$/\1/p' $(VDRDI
ARCHIVE = $(PLUGIN)-$(VERSION)
PACKAGE = vdr-$(ARCHIVE)
### Includes and Defines (add further entries here):
### Includes, Defines and dependencies (add further entries here):
INCLUDES += -I$(VDRDIR)/include
DEFINES += $(CONFIG) -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
_CFLAGS = $(DEFINES) $(INCLUDES) \
$(shell pkg-config --cflags libavcodec libavformat) \
`pkg-config --cflags x11 x11-xcb xcb xcb-xv xcb-shm xcb-dpms xcb-atom\
xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\
`pkg-config --cflags gl glu` \
$(if $(findstring USE_VDPAU,$(CONFIG)), \
`pkg-config --cflags vdpau`) \
$(if $(findstring USE_VAAPI,$(CONFIG)), \
`pkg-config --cflags libva-x11 libva-glx libva`) \
$(if $(findstring USE_ALSA,$(CONFIG)), \
`pkg-config --cflags alsa`)
#override _CFLAGS += -Werror
override CXXFLAGS += $(_CFLAGS)
override CFLAGS += $(_CFLAGS)
LIBS += -lrt \
$(shell pkg-config --libs libavcodec libavformat) \
`pkg-config --libs x11 x11-xcb xcb xcb-xv xcb-shm xcb-dpms xcb-atom\
xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\
`pkg-config --libs gl glu` \
$(if $(findstring USE_VDPAU,$(CONFIG)), \
`pkg-config --libs vdpau`) \
$(if $(findstring USE_VAAPI,$(CONFIG)), \
`pkg-config --libs libva-x11 libva-glx libva`) \
$(if $(findstring USE_ALSA,$(CONFIG)), \
`pkg-config --libs alsa`)
### The object files (add further files here):
OBJS = $(PLUGIN).o softhddev.o video.o audio.o codec.o ringbuffer.o
@@ -105,6 +110,8 @@ DEPFILE = .dependencies
$(DEPFILE): Makefile
@$(MAKEDEP) $(DEFINES) $(INCLUDES) $(SRCS) >$@
$(OBJS): Makefile
-include $(DEPFILE)
### Internationalization (I18N):
@@ -137,7 +144,7 @@ i18n: $(I18Nmsgs) $(I18Npot)
### Targets:
libvdr-$(PLUGIN).so: $(OBJS) Makefile
$(CXX) $(CXXFLAGS) -shared $(OBJS) -o $@ $(LDFLAGS)
$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared -fPIC $(OBJS) -o $@ $(LIBS)
@cp --remove-destination $@ $(LIBDIR)/$@.$(APIVERSION)
dist: $(I18Npo) clean
@@ -163,5 +170,5 @@ indent:
done
video_test: video.c
$(CC) -DVIDEO_TEST -DVERSION='"$(VERSION)"' $(CFLAGS) $(LDFLAGS) $(LIBS) \
-O0 -g -o $@ $<
$(CC) -DVIDEO_TEST -DVERSION='"$(VERSION)"' $(CFLAGS) $(LDFLAGS) $< $(LIBS) \
-o $@

View File

@@ -33,7 +33,7 @@ A software and GPU emulated HD output device plugin for VDR.
o Audio FFMpeg/Alsa/Analog
o Audio FFMpeg/Alsa/Digital
o Audio FFMpeg/OSS/Analog
o planned: Alsa HDMI/SPDIF Passthrough
o Alsa HDMI/SPDIF Passthrough
o planned: OSS HDMI/SPDIF Passthrough
To compile you must have the 'requires' installed.
@@ -95,6 +95,9 @@ Setup: /etc/vdr/setup.conf
softhddevice.MakePrimary = 1
0 = no change, 1 make softhddevice primary at start
softhddevice.HideMainMenuEntry = 0
0 = show softhddevice main menu entry, 1 = hide entry
<res> of the next parameters is 567i, 720p, 1080i_fake or 1080i.
1080i_fake is 1280x1080 or 1440x1080
1080i is "real" 1920x1080
@@ -122,12 +125,33 @@ Setup: /etc/vdr/setup.conf
softhddevice.AudioPassthrough = 0
0 = none, 1 = AC-3
Setup: /etc/vdr/remote.conf
------
Add "XKeySym." definitions to /etc/vdr/remote.conf to control
the vdr and plugin with the connected input device.
fe.
XKeySym.Up Up
XKeySym.Down Down
...
Additional to the x11 input sends the window close button "Close".
fe.
XKeySym.Power Close
Commandline:
------------
Use vdr -h to see the command line arguments support by the plugin.
Running:
--------
Click into video window to toggle fullscreen/window mode, only if you
have a window manager running.
Warning:
--------
libav is not supported, expect many bugs with it.

38
Todo
View File

@@ -19,17 +19,13 @@ GNU Affero General Public License for more details.
$Id: $
missing:
video out with xv
video out with opengl
software decoder for xv / opengl
software deinterlace
auto crop
atmolight
zoom/fit-zoom 4:3
multistream handling
disable screensaver
disable window cursor
zoom/fit-zoom 4:3 (SetVideoDisplayFormat, SetVideoFormat?)
ITU BT601, ITU BT709 (HD), RGB studio levels (16-235)?
suspend output / energie saver: stop audio, stop video, configurable
Option deinterlace off / deinterlace force!
Make output drivers better moduluar.
vdpau:
1080i with temporal spatial and level 1 scaling too slow with my GT 520
@@ -38,6 +34,7 @@ vdpau:
Improve OSD handling, show only what is used. Big OSD costs performance
VdpPreemptionCallback handling
hard channel switch
suspendoutput didn't show logo or black picture.
libva:
hard channel switch
@@ -57,16 +54,14 @@ libva-vdpau-driver:
libva-xvba-driver:
x11:
support resize of x11 window
support fullscreen window
support fullscreen / window toggle
close window should send power button
disable cursor
disable screensaver
audio/alsa:
done? video/audio asyncron
random crashes in av_parser_parse2, when switching channels
sometimes alsa hangs
fixed? snd_pcm_state: Assertion `pcm' failed. while switching channels
(thread problem)
better downmix of >2 channels on 2 channel hardware
remix support of unsupported sample rates
@@ -74,6 +69,9 @@ audio/alsa:
ffmpeg didn't support resample of 5 to 2 channels
CodecAudioOpen can fail "can't open audio codec" and does Fatal exit.
audio:
write TS -> PES parser, which feeds audio before the next start packet
audio/oss:
alsa oss emulation mixer "pcm" not working
ring buffer overflow with alsa oss emulation
@@ -81,6 +79,7 @@ audio/oss:
HDMI/SPDIF Passthrough:
only AC-3 written
Channels are wrong setup, if changing setting during operation.
split pcm and ac-3 out into two devices
playback of recording
pause is not reset, when replay exit
@@ -91,6 +90,17 @@ setup:
Setup of output type.
Setup of display type.
Setup 4:3 zoom type
Setup parameters are not used until restart.
Some setup parameters are not used until restart.
Can a notice be added to the setup menu?
576i, 720p, fake 1080i, 1080i
future features (not planed for 1.0 - 1.5)
video out with xv
video out with opengl
video out with xvba
software decoder for xv / opengl
atmolight support
multistream handling
upmix stereo to AC-3

44
audio.c
View File

@@ -856,23 +856,9 @@ static int AlsaSetup(int *freq, int *channels)
if (!AlsaPCMHandle) { // alsa not running yet
return -1;
}
#if 1
#if 1 // easy alsa hw setup way
// flush any buffered data
#ifndef SEARCH_HDMI_BUG2
#ifdef USE_AUDIO_THREAD
if (AudioRunning) {
while (AudioRunning) {
AlsaFlushBuffer = 1;
usleep(1 * 1000);
}
AlsaFlushBuffer = 0;
} else
#endif
{
AlsaFlushBuffers();
}
#endif
AudioPTS = INT64_C(0x8000000000000000);
AudioFlushBuffers();
if (1) { // close+open to fix hdmi no sound bugs
handle = AlsaPCMHandle;
@@ -1449,7 +1435,6 @@ static int OssSetup(int *freq, int *channels)
AudioRunning = 0;
OssFlushBuffers();
}
AudioPTS = INT64_C(0x8000000000000000);
ret = 0;
@@ -1711,17 +1696,18 @@ void AudioFlushBuffers(void)
{
#ifdef USE_ALSA
#ifdef USE_AUDIO_THREAD
if (AudioRunning) {
while (AudioRunning) {
AlsaFlushBuffer = 1;
// signal thread to flush buffers
if (AudioThread) {
AlsaFlushBuffer = 1;
do {
AudioRunning = 1; // wakeup in case of sleeping
pthread_cond_signal(&AudioStartCond);
usleep(1 * 1000);
}
AlsaFlushBuffer = 0;
} else
#endif
{
AlsaFlushBuffers();
} while (AlsaFlushBuffer); // wait until flushed
}
#else
AlsaFlushBuffers();
#endif
#endif
#ifdef USE_OSS
OssFlushBuffers();
@@ -1749,12 +1735,12 @@ void AudioPoller(void)
int AudioFreeBytes(void)
{
#ifdef USE_ALSA
return RingBufferFreeBytes(AlsaRingBuffer);
return AlsaRingBuffer ? RingBufferFreeBytes(AlsaRingBuffer) : INT32_MAX;
#endif
#ifdef USE_OSS
return RingBufferFreeBytes(OssRingBuffer);
return OssRingBuffer ? RingBufferFreeBytes(OssRingBuffer) : INT32_MAX;
#endif
return -1;
return INT32_MAX; // no driver, much space
}
/**

View File

@@ -35,6 +35,11 @@
#include <libavcodec/avcodec.h>
#ifndef __USE_GNU
#define __USE_GNU
#endif
#include <pthread.h>
#include "misc.h"
#include "softhddev.h"
@@ -52,7 +57,13 @@ static char ConfigVdpauDecoder = 1; ///< use vdpau decoder, if possible
#define ConfigVdpauDecoder 0 ///< no vdpau decoder configured
#endif
static const char DeviceStopped = 1; ///< flag device stopped
static char ConfigFullscreen; ///< fullscreen modus
static char ConfigSuspendClose = 1; ///< suspend should close devices
static char ConfigSuspendX11 = 1; ///< suspend should stop x11
static pthread_mutex_t SuspendLockMutex; ///< suspend lock mutex
static volatile char VideoFreezed; ///< video freezed
//////////////////////////////////////////////////////////////////////////////
// Audio
@@ -195,13 +206,16 @@ int PlayAudio(const uint8_t * data, int size,
// channel switch: SetAudioChannelDevice: SetDigitalAudioDevice:
if (VideoFreezed) { // video freezed
return 0;
}
if (NewAudioStream) {
// FIXME: does this clear the audio ringbuffer?
CodecAudioClose(MyAudioDecoder);
AudioCodecID = CODEC_ID_NONE;
NewAudioStream = 0;
}
if (SkipAudio) {
if (SkipAudio) { // skip audio
return size;
}
// PES header 0x00 0x00 0x01 ID
@@ -313,7 +327,7 @@ int PlayAudio(const uint8_t * data, int size,
void Mute(void)
{
SkipAudio = 1;
AudioSetVolume(0);
//AudioSetVolume(0);
}
/**
@@ -348,8 +362,8 @@ static AVPacket VideoPacketRb[VIDEO_PACKET_MAX];
static int VideoPacketWrite; ///< write pointer
static int VideoPacketRead; ///< read pointer
static atomic_t VideoPacketsFilled; ///< how many of the buffer is used
static volatile char VideoFreezed; ///< video freezed
static volatile char VideoClearBuffers; ///< clear video buffers
static volatile char SkipVideo; ///< skip video
#ifdef DEBUG
static int VideoMaxPacketSize; ///< biggest used packet buffer
@@ -567,19 +581,23 @@ int VideoDecode(void)
/**
** Try video start.
**
** Could be called, when already started.
** NOT TRUE: Could be called, when already started.
*/
static void StartVideo(void)
{
VideoInit(X11DisplayName);
if (ConfigFullscreen) {
// FIXME: not good looking, mapped and then resized.
VideoSetFullscreen(1);
}
VideoOsdInit();
if (!MyVideoDecoder) {
VideoHwDecoder *hw_decoder;
if ((hw_decoder = VideoNewHwDecoder())) {
MyVideoDecoder = CodecVideoNewDecoder(hw_decoder);
VideoCodecID = CODEC_ID_NONE;
}
VideoCodecID = CODEC_ID_NONE;
}
VideoPacketInit();
}
@@ -648,6 +666,12 @@ int PlayVideo(const uint8_t * data, int size)
if (!MyVideoDecoder) { // no x11 video started
return size;
}
if (SkipVideo) { // skip video
return size;
}
if (VideoFreezed) { // video freezed
return 0;
}
if (NewVideoStream) { // channel switched
Debug(3, "video: new stream %d\n", GetMsTicks() - VideoSwitch);
// FIXME: hack to test results
@@ -668,7 +692,7 @@ int PlayVideo(const uint8_t * data, int size)
n = data[8]; // header size
// wrong size
if (size < 9 + n + 4) {
Error(_("[softhddev] invalid video packet\n"));
Error(_("[softhddev] invalid video packet %d bytes\n"), size);
return size;
}
// FIXME: hack to test results
@@ -735,6 +759,16 @@ int PlayVideo(const uint8_t * data, int size)
Debug(3, "video: h264 detected\n");
VideoCodecID = CODEC_ID_H264;
}
// Access Unit Delimiter (BBC-HD)
// FIXME: the 4 offset are try & error selected
} else if ((data[6] & 0xC0) == 0x80 && !check[4 + 0] && !check[4 + 1]
&& !check[4 + 2] && check[4 + 3] == 0x1 && check[4 + 4] == 0x09) {
if (VideoCodecID == CODEC_ID_H264) {
VideoNextPacket(CODEC_ID_H264);
} else {
Debug(3, "video: h264 detected\n");
VideoCodecID = CODEC_ID_H264;
}
} else {
// this happens when vdr sends incomplete packets
if (VideoCodecID == CODEC_ID_NONE) {
@@ -761,6 +795,7 @@ int PlayVideo(const uint8_t * data, int size)
*/
void SetPlayMode(void)
{
Resume();
if (MyVideoDecoder) {
if (VideoCodecID != CODEC_ID_NONE) {
NewVideoStream = 1;
@@ -774,6 +809,7 @@ void SetPlayMode(void)
}
VideoFreezed = 0;
SkipAudio = 0;
SkipVideo = 0;
}
/**
@@ -910,12 +946,13 @@ void OsdClose(void)
*/
void OsdDrawARGB(int x, int y, int height, int width, const uint8_t * argb)
{
Resume();
VideoOsdDrawARGB(x, y, height, width, argb);
}
//////////////////////////////////////////////////////////////////////////////
static char StartX11Server; ///< flag start the x11 server
static char ConfigStartX11Server; ///< flag start the x11 server
/**
** Return command line help string.
@@ -924,6 +961,7 @@ const char *CommandLineHelp(void)
{
return " -a device\taudio device (fe. alsa: hw:0,0 oss: /dev/dsp)\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";
}
@@ -940,13 +978,16 @@ int ProcessArgs(int argc, char *const argv[])
// Parse arguments.
//
for (;;) {
switch (getopt(argc, argv, "-a:d:g:x")) {
switch (getopt(argc, argv, "-a:d:fg:x")) {
case 'a': // audio device
AudioSetDevice(optarg);
continue;
case 'd': // x11 display name
X11DisplayName = optarg;
continue;
case 'f': // fullscreen mode
ConfigFullscreen = 1;
continue;
case 'g': // geometry
if (VideoSetGeometry(optarg) < 0) {
fprintf(stderr,
@@ -956,7 +997,7 @@ int ProcessArgs(int argc, char *const argv[])
}
continue;
case 'x': // x11 server
StartX11Server = 1;
ConfigStartX11Server = 1;
continue;
case EOF:
break;
@@ -1095,13 +1136,16 @@ void SoftHdDeviceExit(void)
CodecExit();
VideoPacketExit();
if (StartX11Server) {
if (ConfigStartX11Server) {
Debug(3, "x-setup: Stop x11 server\n");
if (X11ServerPid) {
kill(X11ServerPid, SIGTERM);
// FIXME: wait for x11 finishing
}
}
pthread_mutex_destroy(&SuspendLockMutex);
}
/**
@@ -1109,15 +1153,17 @@ void SoftHdDeviceExit(void)
*/
void Start(void)
{
if (StartX11Server) {
if (ConfigStartX11Server) {
StartXServer();
}
CodecInit();
// FIXME: AudioInit for HDMI after X11 startup
AudioInit();
if (!StartX11Server) {
if (!ConfigStartX11Server) {
StartVideo();
}
pthread_mutex_init(&SuspendLockMutex, NULL);
}
/**
@@ -1138,3 +1184,57 @@ void Stop(void)
void MainThreadHook(void)
{
}
//////////////////////////////////////////////////////////////////////////////
// Suspend/Resume
//////////////////////////////////////////////////////////////////////////////
/**
** Suspend plugin.
*/
void Suspend(void)
{
pthread_mutex_lock(&SuspendLockMutex);
if (SkipVideo && SkipAudio) { // already suspended
pthread_mutex_unlock(&SuspendLockMutex);
return;
}
Debug(3, "[softhddev]%s:\n", __FUNCTION__);
SkipVideo = 1;
SkipAudio = 1;
pthread_mutex_unlock(&SuspendLockMutex);
if (ConfigSuspendClose) {
pthread_mutex_lock(&SuspendLockMutex);
// FIXME: close audio
// FIXME: close video
pthread_mutex_unlock(&SuspendLockMutex);
}
if (ConfigSuspendX11) {
// FIXME: stop x11, if started
}
}
/**
** Resume plugin.
*/
void Resume(void)
{
if (!SkipVideo && !SkipAudio) { // we are not suspended
return;
}
Debug(3, "[softhddev]%s:\n", __FUNCTION__);
if (ConfigSuspendX11) {
}
if (ConfigSuspendClose) {
pthread_mutex_lock(&SuspendLockMutex);
pthread_mutex_unlock(&SuspendLockMutex);
}
SkipVideo = 0;
SkipAudio = 0;
}

View File

@@ -76,6 +76,10 @@ extern "C"
/// C plugin main thread hook
extern void MainThreadHook(void);
/// Suspend plugin
extern void Suspend(void);
/// Resume plugin
extern void Resume(void);
#ifdef __cplusplus
}
#endif

View File

@@ -42,11 +42,11 @@ extern "C"
//////////////////////////////////////////////////////////////////////////////
static const char *const VERSION = "0.3.0";
static const char *const VERSION = "0.3.1";
static const char *const DESCRIPTION =
trNOOP("A software and GPU emulated HD device");
//static const char *MAINMENUENTRY = trNOOP("Soft-HD-Device");
static const char *MAINMENUENTRY = trNOOP("Suspend Soft-HD-Device");
static class cSoftHdDevice *MyDevice;
//////////////////////////////////////////////////////////////////////////////
@@ -58,6 +58,7 @@ static const char *const Resolution[RESOLUTIONS] = {
};
static char ConfigMakePrimary; ///< config primary wanted
static char ConfigHideMainMenuEntry; ///< config hide main menu entry
/// config deinterlace
static int ConfigVideoDeinterlace[RESOLUTIONS];
@@ -131,8 +132,10 @@ extern "C" void FeedKeyPress(const char *keymap, const char *key, int repeat,
class cSoftOsd:public cOsd
{
int Level; ///< level: subtitle
public:
cSoftOsd(int, int, uint);
cSoftOsd(int, int, uint);
virtual ~ cSoftOsd(void);
virtual void Flush(void);
// virtual void SetActive(bool);
@@ -145,6 +148,7 @@ cSoftOsd::cSoftOsd(int left, int top, uint level)
dsyslog("[softhddev]%s: %dx%d+%d+%d, %d\n", __FUNCTION__, OsdWidth(),
OsdHeight(), left, top, level);
this->Level = level;
//SetActive(true);
}
@@ -222,8 +226,24 @@ void cSoftOsd::Flush(void)
}
}
OsdDrawARGB(Left() + bitmap->X0(), Top() + bitmap->Y0(),
bitmap->Width(), bitmap->Height(), argb);
// 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(),
bitmap->Width(), bitmap->Height(), argb);
} else {
OsdDrawARGB(Left() + bitmap->X0(), Top() + bitmap->Y0(),
bitmap->Width(), bitmap->Height(), argb);
}
bitmap->Clean();
free(argb);
@@ -306,6 +326,7 @@ class cMenuSetupSoft:public cMenuSetupPage
{
protected:
int MakePrimary;
int HideMainMenuEntry;
int Scaling[RESOLUTIONS];
int Deinterlace[RESOLUTIONS];
int SkipChromaDeinterlace[RESOLUTIONS];
@@ -338,7 +359,7 @@ static inline cOsdItem *SeparatorItem(const char *label)
cMenuSetupSoft::cMenuSetupSoft(void)
{
static const char *const deinterlace[] = {
"Bob", "Weave", "Temporal", "TemporalSpatial", "Software"
"Bob", "Weave/None", "Temporal", "TemporalSpatial", "Software"
};
static const char *const scaling[] = {
"Normal", "Fast", "HQ", "Anamorphic"
@@ -356,6 +377,9 @@ cMenuSetupSoft::cMenuSetupSoft(void)
MakePrimary = ConfigMakePrimary;
Add(new cMenuEditBoolItem(tr("Make primary device"), &MakePrimary,
tr("no"), tr("yes")));
HideMainMenuEntry = ConfigHideMainMenuEntry;
Add(new cMenuEditBoolItem(tr("Hide main menu entry"), &HideMainMenuEntry,
tr("no"), tr("yes")));
//
// video
//
@@ -397,6 +421,8 @@ void cMenuSetupSoft::Store(void)
int i;
SetupStore("MakePrimary", ConfigMakePrimary = MakePrimary);
SetupStore("HideMainMenuEntry", ConfigHideMainMenuEntry =
HideMainMenuEntry);
for (i = 0; i < RESOLUTIONS; ++i) {
char buf[128];
@@ -449,8 +475,15 @@ class cSoftHdDevice:public cDevice
virtual bool Poll(cPoller &, int = 0);
virtual bool Flush(int = 0);
virtual int64_t GetSTC(void);
virtual void GetVideoSize(int &width, int &height, double &aspect)
{
width = 1920;
height = 1080;
aspect = (double)width / height;
}
virtual void GetOsdSize(int &, int &, double &);
virtual int PlayVideo(const uchar *, int);
//virtual int PlayTsVideo(const uchar *, int);
#ifdef USE_OSS // FIXME: testing only oss
virtual int PlayTsAudio(const uchar *, int);
@@ -467,11 +500,13 @@ class cSoftHdDevice:public cDevice
virtual int ProvidesCa(const cChannel *) const;
#if 0
// SPU facilities
private:
cDvbSpuDecoder * spuDecoder;
public:
virtual cSpuDecoder * GetSpuDecoder(void);
#endif
protected:
virtual void MakePrimaryDevice(bool);
@@ -481,7 +516,9 @@ cSoftHdDevice::cSoftHdDevice(void)
{
//dsyslog("[softhddev]%s\n", __FUNCTION__);
#if 0
spuDecoder = NULL;
#endif
}
cSoftHdDevice::~cSoftHdDevice(void)
@@ -499,15 +536,18 @@ void cSoftHdDevice::MakePrimaryDevice(bool on)
}
}
int cSoftHdDevice::ProvidesCa(
__attribute__ ((unused)) const cChannel * channel) const
{
//dsyslog("[softhddev]%s: %p\n", __FUNCTION__, channel);
int cSoftHdDevice::ProvidesCa(
__attribute__ ((unused)) const cChannel *
channel) const
{
//dsyslog("[softhddev]%s: %p\n", __FUNCTION__, channel);
return 0;
}
return 0;
}
cSpuDecoder *cSoftHdDevice::GetSpuDecoder(void)
#if 0
cSpuDecoder *cSoftHdDevice::GetSpuDecoder(void)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
@@ -517,6 +557,8 @@ cSpuDecoder *cSoftHdDevice::GetSpuDecoder(void)
return spuDecoder;
}
#endif
bool cSoftHdDevice::HasDecoder(void) const
{
return true;
@@ -540,7 +582,7 @@ bool cSoftHdDevice::SetPlayMode(ePlayMode PlayMode)
case pmVideoOnly:
break;
case pmNone:
break;
return true;
case pmExtern_THIS_SHOULD_BE_AVOIDED:
break;
default:
@@ -584,6 +626,9 @@ void cSoftHdDevice::Play(void)
::Play();
}
/**
** Puts the device into "freeze frame" mode.
*/
void cSoftHdDevice::Freeze(void)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
@@ -759,11 +804,13 @@ class cPluginSoftHdDevice:public cPlugin
virtual void Stop(void);
// virtual void Housekeeping(void);
virtual void MainThreadHook(void);
// virtual const char *MainMenuEntry(void);
// virtual cOsdObject *MainMenuAction(void);
virtual const char *MainMenuEntry(void);
virtual cOsdObject *MainMenuAction(void);
virtual cMenuSetupPage *SetupMenu(void);
virtual bool SetupParse(const char *, const char *);
// virtual bool Service(const char *Id, void *Data = NULL);
// virtual bool Service(const char *, void * = NULL);
virtual const char **SVDRPHelpPages(void);
virtual cString SVDRPCommand(const char *, const char *, int &);
};
cPluginSoftHdDevice::cPluginSoftHdDevice(void)
@@ -820,15 +867,14 @@ bool cPluginSoftHdDevice::Initialize(void)
return true;
}
/**
** Start any background activities the plugin shall perform.
*/
bool cPluginSoftHdDevice::Start(void)
{
const cDevice *primary;
// Start any background activities the plugin shall perform.
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
primary = cDevice::PrimaryDevice();
if (MyDevice != primary) {
if (!MyDevice->IsPrimaryDevice()) {
isyslog("[softhddev] softhddevice is not the primary device!");
if (ConfigMakePrimary) {
// Must be done in the main thread
@@ -860,14 +906,31 @@ void cPluginSoftHdDevice::Housekeeping(void)
// Perform any cleanup or other regular tasks.
}
#endif
/**
** Create main menu entry.
*/
const char *cPluginSoftHdDevice::MainMenuEntry(void)
{
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
return tr(MAINMENUENTRY);
return NULL;
return ConfigHideMainMenuEntry ? NULL : tr(MAINMENUENTRY);
}
#endif
/**
** Perform the action when selected from the main VDR menu.
*/
cOsdObject *cPluginSoftHdDevice::MainMenuAction(void)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
cDevice::PrimaryDevice()->StopReplay();
Suspend();
ShutdownHandler.SetUserInactive();
return NULL;
}
/**
** Called for every plugin once during every cycle of VDR's main program
@@ -882,29 +945,15 @@ void cPluginSoftHdDevice::MainThreadHook(void)
cDevice::SetPrimaryDevice(MyDevice->DeviceNumber() + 1);
DoMakePrimary = 0;
}
// check if user is inactive, automatic enter suspend mode
if (ShutdownHandler.IsUserInactive()) {
// this is regular called, but guarded against double calls
Suspend();
}
::MainThreadHook();
}
#if 0
bool cPluginSoftHdDevice::Service(const char *Id, void *Data)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
return false;
}
cOsdObject *cPluginSoftHdDevice::MainMenuAction(void)
{
// Perform the action when selected from the main VDR menu.
dsyslog("[softhddev]%s:\n", __FUNCTION__);
return NULL;
}
#endif
/**
** Return our setup menu.
*/
@@ -923,13 +972,16 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
int i;
char buf[128];
dsyslog("[softhddev]%s: '%s' = '%s'\n", __FUNCTION__, name, value);
//dsyslog("[softhddev]%s: '%s' = '%s'\n", __FUNCTION__, name, value);
// FIXME: handle the values
if (!strcmp(name, "MakePrimary")) {
ConfigMakePrimary = atoi(value);
return true;
}
if (!strcmp(name, "HideMainMenuEntry")) {
ConfigHideMainMenuEntry = atoi(value);
return true;
}
for (i = 0; i < RESOLUTIONS; ++i) {
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Scaling");
if (!strcmp(name, buf)) {
@@ -975,4 +1027,51 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
return false;
}
#if 0
bool cPluginSoftHdDevice::Service(const char *Id, void *Data)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
return false;
}
#endif
//----------------------------------------------------------------------------
// cPlugin SVDRP
//----------------------------------------------------------------------------
/**
** Return SVDRP commands help pages.
**
** return a pointer to a list of help strings for all of the plugin's
** SVDRP commands.
*/
const char **cPluginSoftHdDevice::SVDRPHelpPages(void)
{
// FIXME: translation?
static const char *text[] = {
"SUSP\n",
" Suspend plugin",
NULL
};
return text;
}
/**
** Handle SVDRP commands.
*/
cString cPluginSoftHdDevice::SVDRPCommand(const char *command,
__attribute__ ((unused)) const char *option,
__attribute__ ((unused)) int &reply_code)
{
if (!strcasecmp(command, "SUSP")) {
Suspend();
return "SoftHdDevice is suspended";
}
return NULL;
}
VDRPLUGINCREATOR(cPluginSoftHdDevice); // Don't touch this!

450
video.c
View File

@@ -94,10 +94,28 @@
#include <xcb/xcb_event.h>
#include <xcb/xcb_atom.h>
#include <xcb/xcb_icccm.h>
#ifdef XCB_ICCCM_NUM_WM_SIZE_HINTS_ELEMENTS
#include <xcb/xcb_ewmh.h>
#else // compatibility hack for old xcb-util
/**
* @brief Action on the _NET_WM_STATE property
*/
typedef enum
{
/* Remove/unset property */
XCB_EWMH_WM_STATE_REMOVE = 0,
/* Add/set property */
XCB_EWMH_WM_STATE_ADD = 1,
/* Toggle property */
XCB_EWMH_WM_STATE_TOGGLE = 2
} xcb_ewmh_wm_state_action_t;
#endif
#include <xcb/xcb_keysyms.h>
#endif
#ifdef USE_GLX
#include <GL/gl.h> // For GL_COLOR_BUFFER_BIT
#include <GL/glx.h>
// only for gluErrorString
#include <GL/glu.h>
@@ -208,6 +226,8 @@ static int VideoWindowY; ///< video outout window y coordinate
static unsigned VideoWindowWidth; ///< video output window width
static unsigned VideoWindowHeight; ///< video output window height
static char VideoSurfaceModesChanged; ///< flag surface modes changed
/// Default deinterlace mode.
static VideoDeinterlaceModes VideoDeinterlace[VideoResolutionMax];
@@ -239,6 +259,8 @@ static VideoZoomModes Video4to3ZoomMode;
static char Video60HzMode; ///< handle 60hz displays
static xcb_atom_t WmDeleteWindowAtom; ///< WM delete message
static xcb_atom_t NetWmState; ///< wm-state message atom
static xcb_atom_t NetWmStateFullscreen; ///< fullscreen wm-state message atom
extern uint32_t VideoSwitch; ///< ticks for channel switch
@@ -915,7 +937,6 @@ struct _vaapi_decoder_
/// flags for put surface for different resolutions groups
unsigned SurfaceFlagsTable[VideoResolutionMax];
unsigned SurfaceFlags; ///< current flags for put surface
enum PixelFormat PixFmt; ///< ffmpeg frame pixfmt
int WrongInterlacedWarned; ///< warning about interlace flag issued
@@ -1017,20 +1038,6 @@ static void VaapiCreateSurfaces(VaapiDecoder * decoder, int width, int height)
Warning(_("video/vaapi: no osd subpicture yet\n"));
return;
}
#if 0
// FIXME: try to fix intel osd bugs
if (vaDestroySubpicture(VaDisplay, VaOsdSubpicture)
!= VA_STATUS_SUCCESS) {
Error(_("video/vaapi: can't destroy subpicture\n"));
}
VaOsdSubpicture = VA_INVALID_ID;
if (vaCreateSubpicture(VaDisplay, VaOsdImage.image_id,
&VaOsdSubpicture) != VA_STATUS_SUCCESS) {
Error(_("video/vaapi: can't create subpicture\n"));
return;
}
#endif
if (VaapiUnscaledOsd) {
if (vaAssociateSubpicture(VaDisplay, VaOsdSubpicture,
@@ -1041,18 +1048,12 @@ static void VaapiCreateSurfaces(VaapiDecoder * decoder, int width, int height)
Error(_("video/vaapi: can't associate subpicture\n"));
}
} else {
int i;
if (vaAssociateSubpicture(VaDisplay, VaOsdSubpicture,
decoder->SurfacesFree, decoder->SurfaceFreeN, 0, 0,
VaOsdImage.width, VaOsdImage.height, 0, 0, width, height, 0)
!= VA_STATUS_SUCCESS) {
Error(_("video/vaapi: can't associate subpicture\n"));
}
for (i = 0; i < decoder->SurfaceFreeN; ++i) {
Debug(4, "video/vaapi: associate %#010x surface\n",
decoder->SurfacesFree[i]);
}
}
}
@@ -1186,8 +1187,12 @@ static void VaapiInitSurfaceFlags(VaapiDecoder * decoder)
for (i = 0; i < VideoResolutionMax; ++i) {
decoder->SurfaceFlagsTable[i] = VA_CLEAR_DRAWABLE;
// FIXME: color space conversion none, ITU-R BT.601, ITU-R BT.709
decoder->SurfaceFlagsTable[i] |= VA_SRC_BT601;
// color space conversion none, ITU-R BT.601, ITU-R BT.709
if (i > VideoResolution567i) {
decoder->SurfaceFlagsTable[i] |= VA_SRC_BT709;
} else {
decoder->SurfaceFlagsTable[i] |= VA_SRC_BT601;
}
// scaling flags FAST, HQ, NL_ANAMORPHIC
// FIXME: need to detect the backend to choose the parameter
@@ -1253,7 +1258,6 @@ static VaapiDecoder *VaapiNewDecoder(void)
decoder->Window = VideoWindow;
VaapiInitSurfaceFlags(decoder);
decoder->SurfaceFlags = decoder->SurfaceFlagsTable[0];
decoder->DeintImages[0].image_id = VA_INVALID_ID;
decoder->DeintImages[1].image_id = VA_INVALID_ID;
@@ -1557,6 +1561,12 @@ static void VaapiUpdateOutput(VaapiDecoder * decoder)
decoder->InputWidth * input_aspect_ratio.num,
decoder->InputHeight * input_aspect_ratio.den, 1024 * 1024);
// InputWidth/Height can be zero = uninitialized
if (!display_aspect_ratio.num || !display_aspect_ratio.den) {
display_aspect_ratio.num = 1;
display_aspect_ratio.den = 1;
}
Debug(3, "video: aspect %d:%d\n", display_aspect_ratio.num,
display_aspect_ratio.den);
@@ -1787,7 +1797,6 @@ static enum PixelFormat Vaapi_get_format(VaapiDecoder * decoder,
decoder->Resolution =
VideoResolutionGroup(video_ctx->width, video_ctx->height,
decoder->Interlaced);
decoder->SurfaceFlags = decoder->SurfaceFlagsTable[decoder->Resolution];
// FIXME: need only to create and destroy surfaces for size changes
// or when number of needed surfaces changed!
VaapiCreateSurfaces(decoder, video_ctx->width, video_ctx->height);
@@ -1886,7 +1895,8 @@ static void VaapiPutSurfaceX11(VaapiDecoder * decoder, VASurfaceID surface,
// video dst
decoder->OutputX, decoder->OutputY, decoder->OutputWidth,
decoder->OutputHeight, NULL, 0,
type | decoder->SurfaceFlags)) != VA_STATUS_SUCCESS) {
type | decoder->SurfaceFlagsTable[decoder->Resolution])) !=
VA_STATUS_SUCCESS) {
// switching video kills VdpPresentationQueueBlockUntilSurfaceIdle
Error(_("video/vaapi: vaPutSurface failed %d\n"), status);
}
@@ -2005,7 +2015,8 @@ static void VaapiPutSurfaceGLX(VaapiDecoder * decoder, VASurfaceID surface,
}
start = GetMsTicks();
if (vaCopySurfaceGLX(decoder->VaDisplay, decoder->GlxSurface[0], surface,
type | decoder->SurfaceFlags) != VA_STATUS_SUCCESS) {
type | decoder->SurfaceFlagsTable[decoder->Resolution]) !=
VA_STATUS_SUCCESS) {
Error(_("video/glx: vaCopySurfaceGLX failed\n"));
return;
}
@@ -2127,7 +2138,6 @@ static void VaapiSetup(VaapiDecoder * decoder,
// FIXME: interlaced not valid here?
decoder->Resolution =
VideoResolutionGroup(width, height, decoder->Interlaced);
decoder->SurfaceFlags = decoder->SurfaceFlagsTable[decoder->Resolution];
VaapiCreateSurfaces(decoder, width, height);
#ifdef USE_GLX
@@ -2330,9 +2340,11 @@ static void VaapiBlackSurface(VaapiDecoder * decoder)
vaPutSurface(decoder->VaDisplay, decoder->BlackSurface,
decoder->Window,
// decoder src
0, 0, VideoWindowWidth, VideoWindowHeight,
decoder->OutputX, decoder->OutputY, decoder->OutputWidth,
decoder->OutputHeight,
// video dst
0, 0, VideoWindowWidth, VideoWindowHeight, NULL, 0,
decoder->OutputX, decoder->OutputY, decoder->OutputWidth,
decoder->OutputHeight, NULL, 0,
VA_FRAME_PICTURE)) != VA_STATUS_SUCCESS) {
Error(_("video/vaapi: vaPutSurface failed %d\n"), status);
}
@@ -2341,9 +2353,8 @@ static void VaapiBlackSurface(VaapiDecoder * decoder)
put1 = GetMsTicks();
Debug(4, "video/vaapi: sync %2u put1 %2u\n", sync - start, put1 - sync);
if (0
&& vaSyncSurface(decoder->VaDisplay,
decoder->BlackSurface) != VA_STATUS_SUCCESS) {
if (0 && vaSyncSurface(decoder->VaDisplay, decoder->BlackSurface)
!= VA_STATUS_SUCCESS) {
Error(_("video/vaapi: vaSyncSurface failed\n"));
}
@@ -2772,10 +2783,16 @@ static void VaapiDisplayFrame(void)
uint32_t put1;
uint32_t put2;
int i;
VaapiDecoder *decoder;
if (VideoSurfaceModesChanged) { // handle changed modes
for (i = 0; i < VaapiDecoderN; ++i) {
VaapiInitSurfaceFlags(VaapiDecoders[i]);
}
VideoSurfaceModesChanged = 0;
}
// look if any stream have a new surface available
for (i = 0; i < VaapiDecoderN; ++i) {
VaapiDecoder *decoder;
VASurfaceID surface;
int filled;
@@ -3376,14 +3393,16 @@ static VdpGetErrorString *VdpauGetErrorString;
static VdpDeviceDestroy *VdpauDeviceDestroy;
static VdpGenerateCSCMatrix *VdpauGenerateCSCMatrix;
static VdpVideoSurfaceQueryCapabilities *VdpauVideoSurfaceQueryCapabilities;
static VdpVideoSurfaceQueryGetPutBitsYCbCrCapabilities
*VdpauVideoSurfaceQueryGetPutBitsYCbCrCapabilities;
static VdpVideoSurfaceQueryGetPutBitsYCbCrCapabilities *
VdpauVideoSurfaceQueryGetPutBitsYCbCrCapabilities;
static VdpVideoSurfaceCreate *VdpauVideoSurfaceCreate;
static VdpVideoSurfaceDestroy *VdpauVideoSurfaceDestroy;
static VdpVideoSurfaceGetParameters *VdpauVideoSurfaceGetParameters;
static VdpVideoSurfaceGetBitsYCbCr *VdpauVideoSurfaceGetBitsYCbCr;
static VdpVideoSurfacePutBitsYCbCr *VdpauVideoSurfacePutBitsYCbCr;
static VdpOutputSurfaceQueryCapabilities *VdpauOutputSurfaceQueryCapabilities;
static VdpOutputSurfaceCreate *VdpauOutputSurfaceCreate;
static VdpOutputSurfaceDestroy *VdpauOutputSurfaceDestroy;
@@ -3395,10 +3414,10 @@ static VdpBitmapSurfaceDestroy *VdpauBitmapSurfaceDestroy;
static VdpBitmapSurfacePutBitsNative *VdpauBitmapSurfacePutBitsNative;
static VdpOutputSurfaceRenderOutputSurface *
VdpauOutputSurfaceRenderOutputSurface;
static VdpOutputSurfaceRenderBitmapSurface *
VdpauOutputSurfaceRenderBitmapSurface;
static VdpOutputSurfaceRenderOutputSurface
*VdpauOutputSurfaceRenderOutputSurface;
static VdpOutputSurfaceRenderBitmapSurface
*VdpauOutputSurfaceRenderBitmapSurface;
static VdpDecoderQueryCapabilities *VdpauDecoderQueryCapabilities;
static VdpDecoderCreate *VdpauDecoderCreate;
@@ -3407,8 +3426,8 @@ static VdpDecoderDestroy *VdpauDecoderDestroy;
static VdpDecoderRender *VdpauDecoderRender;
static VdpVideoMixerQueryFeatureSupport *VdpauVideoMixerQueryFeatureSupport;
static VdpVideoMixerQueryAttributeSupport *
VdpauVideoMixerQueryAttributeSupport;
static VdpVideoMixerQueryAttributeSupport
*VdpauVideoMixerQueryAttributeSupport;
static VdpVideoMixerCreate *VdpauVideoMixerCreate;
static VdpVideoMixerSetFeatureEnables *VdpauVideoMixerSetFeatureEnables;
@@ -3419,18 +3438,18 @@ static VdpVideoMixerRender *VdpauVideoMixerRender;
static VdpPresentationQueueTargetDestroy *VdpauPresentationQueueTargetDestroy;
static VdpPresentationQueueCreate *VdpauPresentationQueueCreate;
static VdpPresentationQueueDestroy *VdpauPresentationQueueDestroy;
static VdpPresentationQueueSetBackgroundColor
*VdpauPresentationQueueSetBackgroundColor;
static VdpPresentationQueueSetBackgroundColor *
VdpauPresentationQueueSetBackgroundColor;
static VdpPresentationQueueGetTime *VdpauPresentationQueueGetTime;
static VdpPresentationQueueDisplay *VdpauPresentationQueueDisplay;
static VdpPresentationQueueBlockUntilSurfaceIdle *
VdpauPresentationQueueBlockUntilSurfaceIdle;
static VdpPresentationQueueQuerySurfaceStatus *
VdpauPresentationQueueQuerySurfaceStatus;
static VdpPresentationQueueBlockUntilSurfaceIdle
*VdpauPresentationQueueBlockUntilSurfaceIdle;
static VdpPresentationQueueQuerySurfaceStatus
*VdpauPresentationQueueQuerySurfaceStatus;
static VdpPresentationQueueTargetCreateX11
*VdpauPresentationQueueTargetCreateX11;
static VdpPresentationQueueTargetCreateX11 *
VdpauPresentationQueueTargetCreateX11;
///@}
///
@@ -3921,6 +3940,95 @@ static inline void VdpauGetProc(const VdpFuncId id, void *addr,
}
}
///
/// Initialize output queue.
///
static void VdpauInitOutputQueue(void)
{
VdpStatus status;
int i;
status =
VdpauPresentationQueueTargetCreateX11(VdpauDevice, VideoWindow,
&VdpauQueueTarget);
if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: can't create presentation queue target: %s\n"),
VdpauGetErrorString(status));
return;
}
status =
VdpauPresentationQueueCreate(VdpauDevice, VdpauQueueTarget,
&VdpauQueue);
if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: can't create presentation queue: %s\n"),
VdpauGetErrorString(status));
VdpauPresentationQueueTargetDestroy(VdpauQueueTarget);
VdpauQueueTarget = 0;
return;
}
VdpauBackgroundColor->red = 0.01;
VdpauBackgroundColor->green = 0.02;
VdpauBackgroundColor->blue = 0.03;
VdpauBackgroundColor->alpha = 1.00;
VdpauPresentationQueueSetBackgroundColor(VdpauQueue, VdpauBackgroundColor);
//
// Create display output surfaces
//
for (i = 0; i < OUTPUT_SURFACES_MAX; ++i) {
VdpRGBAFormat format;
format = VDP_RGBA_FORMAT_B8G8R8A8;
// FIXME: does a 10bit rgba produce a better output?
// format = VDP_RGBA_FORMAT_R10G10B10A2;
status =
VdpauOutputSurfaceCreate(VdpauDevice, format, VideoWindowWidth,
VideoWindowHeight, VdpauSurfacesRb + i);
if (status != VDP_STATUS_OK) {
Fatal(_("video/vdpau: can't create output surface: %s\n"),
VdpauGetErrorString(status));
}
Debug(3, "video/vdpau: created output surface %dx%d with id 0x%08x\n",
VideoWindowWidth, VideoWindowHeight, VdpauSurfacesRb[i]);
}
}
///
/// Cleanup output queue.
///
static void VdpauExitOutputQueue(void)
{
int i;
if (VdpauQueue) {
VdpauPresentationQueueDestroy(VdpauQueue);
VdpauQueue = 0;
}
if (VdpauQueueTarget) {
VdpauPresentationQueueTargetDestroy(VdpauQueueTarget);
VdpauQueueTarget = 0;
}
//
// destroy display output surfaces
//
for (i = 0; i < OUTPUT_SURFACES_MAX; ++i) {
VdpStatus status;
Debug(4, "video/vdpau: destroy output surface with id 0x%08x\n",
VdpauSurfacesRb[i]);
if (VdpauSurfacesRb[i] != VDP_INVALID_HANDLE) {
status = VdpauOutputSurfaceDestroy(VdpauSurfacesRb[i]);
if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: can't destroy output surface: %s\n"),
VdpauGetErrorString(status));
}
VdpauSurfacesRb[i] = VDP_INVALID_HANDLE;
}
}
}
///
/// VDPAU setup.
///
@@ -3995,8 +4103,10 @@ static void VideoVdpauInit(const char *display_name)
&VdpauVideoSurfaceGetBitsYCbCr, "VideoSurfaceGetBitsYCbCr");
VdpauGetProc(VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR,
&VdpauVideoSurfacePutBitsYCbCr, "VideoSurfacePutBitsYCbCr");
VdpauGetProc(VDP_FUNC_ID_OUTPUT_SURFACE_QUERY_CAPABILITIES,
&VdpauOutputSurfaceQueryCapabilities,
"OutputSurfaceQueryCapabilities");
#if 0
VdpauGetProc(VDP_FUNC_ID_OUTPUT_SURFACE_QUERY_CAPABILITIES, &, "");
VdpauGetProc
(VDP_FUNC_ID_OUTPUT_SURFACE_QUERY_GET_PUT_BITS_NATIVE_CAPABILITIES, &,
"");
@@ -4115,33 +4225,6 @@ static void VideoVdpauInit(const char *display_name)
// vdp_preemption_callback_register
//
// Create presentation queue, only one queue pro window
//
status =
VdpauPresentationQueueTargetCreateX11(VdpauDevice, VideoWindow,
&VdpauQueueTarget);
if (status != VDP_STATUS_OK) {
Fatal(_("video/vdpau: can't create presentation queue target: %s\n"),
VdpauGetErrorString(status));
// FIXME: no fatal errors
}
status =
VdpauPresentationQueueCreate(VdpauDevice, VdpauQueueTarget,
&VdpauQueue);
if (status != VDP_STATUS_OK) {
Fatal(_("video/vdpau: can't create presentation queue: %s\n"),
VdpauGetErrorString(status));
}
VdpauBackgroundColor->red = 0.01;
VdpauBackgroundColor->green = 0.02;
VdpauBackgroundColor->blue = 0.03;
VdpauBackgroundColor->alpha = 1.00;
VdpauPresentationQueueSetBackgroundColor(VdpauQueue, VdpauBackgroundColor);
//
// Look which levels of high quality scaling are supported
//
@@ -4244,7 +4327,7 @@ static void VideoVdpauInit(const char *display_name)
VdpauVideoSurfaceQueryCapabilities(VdpauDevice, VDP_CHROMA_TYPE_420,
&flag, &max_width, &max_height);
if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: can't create output surface: %s\n"),
Error(_("video/vdpau: can't query video surface: %s\n"),
VdpauGetErrorString(status));
}
if (flag) {
@@ -4256,7 +4339,7 @@ static void VideoVdpauInit(const char *display_name)
VdpauVideoSurfaceQueryCapabilities(VdpauDevice, VDP_CHROMA_TYPE_422,
&flag, &max_width, &max_height);
if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: can't create output surface: %s\n"),
Error(_("video/vdpau: can't query video surface: %s\n"),
VdpauGetErrorString(status));
}
if (flag) {
@@ -4268,7 +4351,7 @@ static void VideoVdpauInit(const char *display_name)
VdpauVideoSurfaceQueryCapabilities(VdpauDevice, VDP_CHROMA_TYPE_444,
&flag, &max_width, &max_height);
if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: can't create output surface: %s\n"),
Error(_("video/vdpau: can't query video surface: %s\n"),
VdpauGetErrorString(status));
}
if (flag) {
@@ -4288,23 +4371,62 @@ static void VideoVdpauInit(const char *display_name)
if (status != VDP_STATUS_OK || !flag) {
Error(_("video/vdpau: doesn't support yv12 video surface\n"));
}
//FIXME: format support and size support
//VdpOutputSurfaceQueryCapabilities
flag = VDP_FALSE;
status =
VdpauOutputSurfaceQueryCapabilities(VdpauDevice,
VDP_RGBA_FORMAT_B8G8R8A8, &flag, &max_width, &max_height);
if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: can't query output surface: %s\n"),
VdpauGetErrorString(status));
}
if (flag) {
Info(_("video/vdpau: 8bit BGRA format with %dx%d supported\n"),
max_width, max_height);
}
flag = VDP_FALSE;
status =
VdpauOutputSurfaceQueryCapabilities(VdpauDevice,
VDP_RGBA_FORMAT_R8G8B8A8, &flag, &max_width, &max_height);
if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: can't query output surface: %s\n"),
VdpauGetErrorString(status));
}
if (flag) {
Info(_("video/vdpau: 8bit RGBA format with %dx%d supported\n"),
max_width, max_height);
}
flag = VDP_FALSE;
status =
VdpauOutputSurfaceQueryCapabilities(VdpauDevice,
VDP_RGBA_FORMAT_R10G10B10A2, &flag, &max_width, &max_height);
if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: can't query output surface: %s\n"),
VdpauGetErrorString(status));
}
if (flag) {
Info(_("video/vdpau: 10bit RGBA format with %dx%d supported\n"),
max_width, max_height);
}
flag = VDP_FALSE;
status =
VdpauOutputSurfaceQueryCapabilities(VdpauDevice,
VDP_RGBA_FORMAT_B10G10R10A2, &flag, &max_width, &max_height);
if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: can't query output surface: %s\n"),
VdpauGetErrorString(status));
}
if (flag) {
Info(_("video/vdpau: 8bit BRGA format with %dx%d supported\n"),
max_width, max_height);
}
// FIXME: does only check for rgba formats, but no action
//
// Create display output surfaces
// Create presentation queue, only one queue pro window
//
for (i = 0; i < OUTPUT_SURFACES_MAX; ++i) {
status =
VdpauOutputSurfaceCreate(VdpauDevice, VDP_RGBA_FORMAT_B8G8R8A8,
VideoWindowWidth, VideoWindowHeight, VdpauSurfacesRb + i);
if (status != VDP_STATUS_OK) {
Fatal(_("video/vdpau: can't create output surface: %s\n"),
VdpauGetErrorString(status));
}
Debug(3, "video/vdpau: created output surface %dx%d with id 0x%08x\n",
VideoWindowWidth, VideoWindowHeight, VdpauSurfacesRb[i]);
}
VdpauInitOutputQueue();
}
///
@@ -4312,38 +4434,13 @@ static void VideoVdpauInit(const char *display_name)
///
static void VideoVdpauExit(void)
{
int i;
if (VdpauDecoders[0]) {
VdpauDelDecoder(VdpauDecoders[0]);
VdpauDecoders[0] = NULL;
}
if (VdpauDevice) {
if (VdpauQueue) {
VdpauPresentationQueueDestroy(VdpauQueue);
VdpauQueue = 0;
}
if (VdpauQueueTarget) {
VdpauPresentationQueueTargetDestroy(VdpauQueueTarget);
VdpauQueueTarget = 0;
}
//
// destroy display output surfaces
//
for (i = 0; i < OUTPUT_SURFACES_MAX; ++i) {
VdpStatus status;
Debug(4, "video/vdpau: destroy output surface with id 0x%08x\n",
VdpauSurfacesRb[i]);
status = VdpauOutputSurfaceDestroy(VdpauSurfacesRb[i]);
if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: can't destroy output surface: %s\n"),
VdpauGetErrorString(status));
}
VdpauSurfacesRb[i] = VDP_INVALID_HANDLE;
}
VdpauExitOutputQueue();
// FIXME: more VDPAU cleanups...
@@ -4380,6 +4477,12 @@ static void VdpauUpdateOutput(VdpauDecoder * decoder)
decoder->InputWidth * input_aspect_ratio.num,
decoder->InputHeight * input_aspect_ratio.den, 1024 * 1024);
// InputWidth/Height can be zero = uninitialized
if (!display_aspect_ratio.num || !display_aspect_ratio.den) {
display_aspect_ratio.num = 1;
display_aspect_ratio.den = 1;
}
Debug(3, "video: aspect %d:%d\n", display_aspect_ratio.num,
display_aspect_ratio.den);
@@ -6013,8 +6116,8 @@ static void VideoEvent(void)
case ClientMessage:
Debug(3, "video/event: ClientMessage\n");
if (event.xclient.data.l[0] == (long)WmDeleteWindowAtom) {
// FIXME: wrong, kills recordings ...
Error(_("video/event: FIXME: wm-delete-message\n"));
Debug(3, "video/event: wm-delete-message\n");
FeedKeyPress("XKeySym", "Close", 0, 0);
}
break;
@@ -6031,7 +6134,12 @@ static void VideoEvent(void)
Debug(3, "video/event: ReparentNotify\n");
break;
case ConfigureNotify:
Debug(3, "video/event: ConfigureNotify\n");
//Debug(3, "video/event: ConfigureNotify\n");
VideoSetVideoMode(event.xconfigure.x, event.xconfigure.y,
event.xconfigure.width, event.xconfigure.height);
break;
case ButtonPress:
VideoSetFullscreen(-1);
break;
case KeyPress:
keysym = XLookupKeysym(&event.xkey, 0);
@@ -6604,6 +6712,22 @@ static void VideoCreateWindow(xcb_window_t parent, xcb_visualid_t visual,
free(reply);
}
}
//
// prepare fullscreen.
//
if ((reply =
xcb_intern_atom_reply(Connection, xcb_intern_atom(Connection, 0,
sizeof("_NET_WM_STATE") - 1, "_NET_WM_STATE"), NULL))) {
NetWmState = reply->atom;
free(reply);
}
if ((reply =
xcb_intern_atom_reply(Connection, xcb_intern_atom(Connection, 0,
sizeof("_NET_WM_STATE_FULLSCREEN") - 1,
"_NET_WM_STATE_FULLSCREEN"), NULL))) {
NetWmStateFullscreen = reply->atom;
free(reply);
}
xcb_map_window(Connection, VideoWindow);
@@ -6664,6 +6788,77 @@ void VideoSetOutputPosition(int x, int y, int width, int height)
VdpauSetOutputPosition(VdpauDecoders[0], x, y, width, height);
}
#endif
#ifdef USE_VAPI
// FIXME: not supported by vaapi without unscaled OSD,
// FIXME: if used to position video inside osd
#endif
}
///
/// Set video window position.
///
/// @param x window x coordinate
/// @param y window y coordinate
/// @param width window width
/// @param height window height
///
/// @note no need to lock, only called from inside the video thread
///
void VideoSetVideoMode(int x, int y, int width, int height)
{
Debug(3, "video: %s %dx%d%+d%+d\n", __FUNCTION__, width, height, x, y);
if ((unsigned)width == VideoWindowWidth
&& (unsigned)height == VideoWindowHeight) {
return; // same size nothing todo
}
VideoWindowWidth = width;
VideoWindowHeight = height;
#ifdef USE_VAAPI
if (VideoVaapiEnabled && VaapiDecoders[0]) {
// FIXME: must update osd surfaces?
VaapiUpdateOutput(VaapiDecoders[0]);
return;
}
#endif
#ifdef USE_VDPAU
if (VideoVdpauEnabled && VdpauDecoders[0]) {
VdpauExitOutputQueue();
VdpauInitOutputQueue();
VdpauUpdateOutput(VdpauDecoders[0]);
return;
}
#endif
}
///
/// Send fullscreen message to window.
///
/// @param onoff -1 toggle, true turn on, false turn off
///
void VideoSetFullscreen(int onoff)
{
xcb_client_message_event_t event;
memset(&event, 0, sizeof(event));
event.response_type = XCB_CLIENT_MESSAGE;
event.format = 32;
event.window = VideoWindow;
event.type = NetWmState;
if (onoff < 0) {
event.data.data32[0] = XCB_EWMH_WM_STATE_TOGGLE;
} else if (onoff) {
event.data.data32[0] = XCB_EWMH_WM_STATE_ADD;
} else {
event.data.data32[0] = XCB_EWMH_WM_STATE_REMOVE;
}
event.data.data32[1] = NetWmStateFullscreen;
xcb_send_event(Connection, XCB_SEND_EVENT_DEST_POINTER_WINDOW,
DefaultRootWindow(XlibDisplay),
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (void *)&event);
Debug(3, "video/x11: send fullscreen message %x %x\n",
event.data.data32[0], event.data.data32[1]);
}
///
@@ -6675,6 +6870,7 @@ void VideoSetDeinterlace(int mode[VideoResolutionMax])
VideoDeinterlace[1] = mode[1];
VideoDeinterlace[2] = mode[2];
VideoDeinterlace[3] = mode[3];
VideoSurfaceModesChanged = 1;
}
///
@@ -6686,6 +6882,7 @@ void VideoSetSkipChromaDeinterlace(int onoff[VideoResolutionMax])
VideoSkipChromaDeinterlace[1] = onoff[1];
VideoSkipChromaDeinterlace[2] = onoff[2];
VideoSkipChromaDeinterlace[3] = onoff[3];
VideoSurfaceModesChanged = 1;
}
///
@@ -6697,6 +6894,7 @@ void VideoSetDenoise(int level[VideoResolutionMax])
VideoSharpen[1] = level[1];
VideoSharpen[2] = level[2];
VideoSharpen[3] = level[3];
VideoSurfaceModesChanged = 1;
}
///
@@ -6708,6 +6906,7 @@ void VideoSetSharpen(int level[VideoResolutionMax])
VideoSharpen[1] = level[1];
VideoSharpen[2] = level[2];
VideoSharpen[3] = level[3];
VideoSurfaceModesChanged = 1;
}
///
@@ -6719,6 +6918,7 @@ void VideoSetScaling(int mode[VideoResolutionMax])
VideoScaling[1] = mode[1];
VideoScaling[2] = mode[2];
VideoScaling[3] = mode[3];
VideoSurfaceModesChanged = 1;
}
///
@@ -6977,7 +7177,7 @@ int main(int argc, char *const argv[])
//
// main loop
//
VideoInit();
VideoInit(NULL);
VideoOsdInit();
for (;;) {
VideoRenderOverlay();

View File

@@ -67,15 +67,18 @@ extern void VideoPollEvent(void);
/// Wakeup display handler.
extern void VideoDisplayWakeup(void);
/// Set video mode.
//extern void VideoSetVideoMode(int, int, int, int);
/// Set video geometry.
extern int VideoSetGeometry(const char *);
/// Set video output position.
extern void VideoSetOutputPosition(int, int, int, int);
/// Set video mode.
extern void VideoSetVideoMode(int, int, int, int);
/// Set video fullscreen mode.
extern void VideoSetFullscreen(int);
/// Set deinterlace.
extern void VideoSetDeinterlace(int[]);