44 Commits
0.3.1 ... 0.4.5

Author SHA1 Message Date
Johns
eed708b9ea Release version 0.4.5. 2012-01-28 13:44:50 +01:00
Johns
60a7c36fa6 Add configurable skip lines at video top + bottom. 2012-01-28 01:44:50 +01:00
Johns
4d74ed1bfc Add auto-crop tolerance configuration. 2012-01-27 23:49:05 +01:00
Johns
c3b924a239 Reduces audio latency, increases audio buffer time. 2012-01-27 23:33:10 +01:00
Johns
f8d198636b Video bug fix.
Made video_test working again.
Disabled VA-API Intel vaAssociateSubpicture workaround.
Fix bug: Must release lock for VideoPollEvent.
Allow faster video and audio sync.
Fix bug: Software decoder use vaPutImage with Intel backend.
Fix bug: Artefacts are shown after mpeg2 channel switch.
Fix bug: VideoReleaseSurface called after VideoExit.
2012-01-27 21:08:37 +01:00
Johns
bcf6ecabc1 Support external players. 2012-01-26 15:00:49 +01:00
Johns
9063b4e3ff Add VDPAU display preemption support. 2012-01-25 15:31:49 +01:00
Johns
e3681812bd Remove pass-through test code. 2012-01-25 15:31:18 +01:00
Johns
9d14522121 Add jpeg support to ebuild. 2012-01-25 15:30:22 +01:00
2dff69dc14 Add support for grab jpeg image. 2012-01-24 22:40:06 +01:00
Johns
5668fa22d2 Video cleanup.
More functions uses new module interface.
Fix bug: VaapiOsdExit doesn't deassociate osd surface.
Fix bug: First OSD can show random pixels.
2012-01-24 22:25:33 +01:00
Johns
c7cebe1aeb Wait for X11 exit and kill it, if not. 2012-01-24 22:20:17 +01:00
Johns
037f582bad Fix still picture handling. 2012-01-24 16:37:11 +01:00
Johns
6ca4d3c44f Fix dead-lock in VdpauExit. 2012-01-24 10:02:39 +01:00
Johns
2ac2eb39c6 Workaround for dead-lock in VdpauExit. 2012-01-24 00:32:07 +01:00
Johns
217545542d Add ac3 pass-through device to OSS module. 2012-01-23 20:23:05 +01:00
Johns
5f43803236 VDPAU: Add primitive software scaler to grab image 2012-01-23 20:04:15 +01:00
Johns
993d831190 VA-API: Add auto-crop support. 2012-01-23 15:40:59 +01:00
Johns
1969b2a0a7 Fix bug: close codec missing. 2012-01-22 22:46:52 +01:00
Johns
0fad02285d AC3 device should be called 'ALSA_AC3_DEVICE'. 2012-01-22 20:53:27 +01:00
Johns
9546233175 Suspend can close and open video and audio device. 2012-01-22 20:49:43 +01:00
Johns
98d2e0f728 Cleanups and Codec..Del.. prototypes. 2012-01-22 17:07:08 +01:00
970493fb23 Use different alsa device for AC3/pass-through. 2012-01-22 16:54:22 +01:00
Johns
329dbc5f07 Add dummy player and control for suspend mode. 2012-01-22 11:12:57 +01:00
Johns
bc8a13e1ef Call VdpauMixerSetup only, if mixer setup. 2012-01-21 21:56:19 +01:00
Johns
bd7e6143c7 Buffertime compile time configurable in ms. 2012-01-21 21:46:47 +01:00
Johns
fa27a1c73a Release Version 0.4.0. 2012-01-21 15:56:45 +01:00
Johns
e32857a27a VDPAU: Add screenshot support. 2012-01-20 21:46:22 +01:00
Johns
5ba88bb822 Use common module prefix. 2012-01-20 19:56:06 +01:00
Johns
0422b6aa5a VDPAU: Add auto-crop support. 2012-01-20 15:33:37 +01:00
Johns
eb024558de VDPAU: Changed OSD alpha calculation. 2012-01-19 22:58:02 +01:00
Johns
1593d5dd83 Fix bug: Used VideoSharpen for denoise settings.
Instant update deinterlace/... configuration changes.
2012-01-19 21:28:38 +01:00
Johns
09f62307d4 Fix bug: AudioExit called without AudioInit crash. 2012-01-19 17:01:02 +01:00
Johns
87f7aa63cc Release Version 0.3.5. 2012-01-19 16:01:05 +01:00
Johns
b1ce88923e Small miscellaneous cleanups. 2012-01-19 00:16:15 +01:00
Johns
c6e66e0787 OSD improvements:
Use OSD size equal to video window.
Update only dirty area(s) of OSD.
Show/mix only used area of OSD.
Fix bug: vpdau use previous resolution for deint, ...
2012-01-18 15:15:37 +01:00
Johns
19d4eeed82 Little speed improved Intel VA-API deinterlace. 2012-01-17 18:53:53 +01:00
Johns
9f668c4750 Fix software deinterlace with VA-API. 2012-01-17 17:41:24 +01:00
Johns
e419742a40 OSS needs kernel headers. 2012-01-16 23:55:45 +01:00
Johns
2cacdc6c90 Debug, if vaapi putsurface is too slow. 2012-01-16 23:54:48 +01:00
Johns
6efe558f78 Fix bug: transposed digits 567 should be 576. 2012-01-16 20:20:01 +01:00
Johns
80100299f3 Disable VA-API if init fails. 2012-01-16 17:05:22 +01:00
Johns
5509d768ac Remove double x11-libs/xcb-util-wm. 2012-01-16 16:39:23 +01:00
Johns
c0d0a4ae7c Audio module cleanup (more to come).
Alsa + OSS can be included/build at the same time.
Alsa or OSS can be runtime selected with -a.
Add audio thread support to OSS module.
Add polled audio support to alsa module.
Removed some debug source code.
2012-01-16 15:42:17 +01:00
15 changed files with 3596 additions and 1161 deletions

View File

@@ -1,4 +1,76 @@
User johns
Date:
Release Version 0.4.5
Add configurable skip lines at video top and bottom.
Add auto-crop tolerance configuration.
Reduces audio latency, increases audio buffer time.
Made video_test working again.
Disabled VA-API Intel vaAssociateSubpicture workaround.
Fix bug: Must release lock for VideoPollEvent.
Allow faster video and audio sync.
Fix bug: Software decoder use vaPutImage with intel backend.
Fix bug: Artefacts are shown after mpeg2 channel switch.
Fix bug: VideoReleaseSurface called after VideoExit.
Support external players.
Add VDPAU display preemption support.
User m.Rcu
Date: Tue Jan 24 22:38:30 CET 2012
Add support for grab jpeg image.
User johns
Date: Tue Jan 24 22:25:33 CET 2012
Fix bug: VaapiOsdExit doesn't deassociate osd surface.
Fix bug: First OSD can show random pixels.
Wait for X11 exit and kill it, if not.
Fix still picture handling.
Fix for dead-lock in VdpauExit.
Workaround for dead-lock in VdpauExit.
VDPAU: Add very primitive software scaler for grab image.
VA-API: Add auto-crop support.
Suspend can close/open X11 window, connection and audio device.
User Morone
Date: Sun Jan 22 16:43:23 CET 2012
Use different alsa devices for AC3/pass-through and pcm.
User johns
Date: Sun Jan 22 11:12:57 CET 2012
Add dummy player and control for suspend mode.
Buffertime compile time configurable in ms.
Date: Sat Jan 21 15:49:16 CET 2012
Release Version 0.4.0
VDPAU: Add grab image support.
VDPAU: Add auto-crop support.
VDPAU: Changed OSD alpha calculation.
Fix bug: Used VideoSharpen for denoise settings.
Instant update deinterlace/... configuration changes.
Fix bug: AudioExit called without AudioInit crash.
Date: Thu Jan 19 15:58:40 CET 2012
Release Version 0.3.5
OSD improvements:
Use OSD size equal to video window.
Update only dirty area(s) of OSD.
Show/mix only used area of OSD.
Fix bug: vpdau use previous resolution for deint, ...
Fix software deinterlace with VA-API.
Fix bug: transposed digits 567 should be 576.
Audio module cleanup:
Alsa + OSS can be included/build at the same time.
Alsa or OSS can be runtime selected with -a.
Add audio thread support to OSS module.
Add polled audio support to alsa module.
Removed some debug source code.
Date: Sun Jan 15 16:56:04 CET 2012
Release Version 0.3.1

View File

@@ -14,6 +14,7 @@ PLUGIN = softhddevice
### The version number of this plugin (taken from the main source file):
VERSION = $(shell grep 'static const char \*const VERSION *=' $(PLUGIN).cpp | awk '{ print $$7 }' | sed -e 's/[";]//g')
GIT_REV = $(shell git describe --always 2>/dev/null)
### Configuration (edit this for your needs)
@@ -22,7 +23,8 @@ CONFIG := #-DDEBUG
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 += -DUSE_OSS
CONFIG += $(shell ls /usr/lib/libjpeg* >/dev/null 2>&1 && echo "-DUSE_JPEG")
CONFIG += -DUSE_OSS
### The C++ compiler and options:
@@ -59,7 +61,8 @@ PACKAGE = vdr-$(ARCHIVE)
INCLUDES += -I$(VDRDIR)/include
DEFINES += $(CONFIG) -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
DEFINES += $(CONFIG) -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' \
$(if $(GIT_REV), -DGIT_REV='"$(GIT_REV)"')
_CFLAGS = $(DEFINES) $(INCLUDES) \
$(shell pkg-config --cflags libavcodec libavformat) \
@@ -87,7 +90,9 @@ LIBS += -lrt \
$(if $(findstring USE_VAAPI,$(CONFIG)), \
`pkg-config --libs libva-x11 libva-glx libva`) \
$(if $(findstring USE_ALSA,$(CONFIG)), \
`pkg-config --libs alsa`)
`pkg-config --libs alsa`) \
$(if $(findstring USE_JPEG,$(CONFIG)), \
-ljpeg)
### The object files (add further files here):
@@ -169,6 +174,6 @@ indent:
indent $$i; unexpand -a $$i > $$i.up; mv $$i.up $$i; \
done
video_test: video.c
video_test: video.c Makefile
$(CC) -DVIDEO_TEST -DVERSION='"$(VERSION)"' $(CFLAGS) $(LDFLAGS) $< $(LIBS) \
-o $@

View File

@@ -24,17 +24,20 @@ A software and GPU emulated HD output device plugin for VDR.
o Video CPU/VA-API
o Video VDPAU/VDPAU
o Video CPU/VDPAU
o Audio FFMpeg/Alsa/Analog
o Audio FFMpeg/Alsa/Digital
o Audio FFMpeg/OSS/Analog
o HDMI/SPDIF Passthrough
o VA-API bob software deinterlace
o Auto-crop
o planned: Video VA-API/Opengl
o planned: Video VDPAU/Opengl
o planned: Video CPU/Xv
o planned: Video CPU/Opengl
o planned: Software Deinterlacer
o planned: Improved Software Deinterlacer (yadif or/and ffmpeg filters)
o planned: Video XvBA/XvBA
o Audio FFMpeg/Alsa/Analog
o Audio FFMpeg/Alsa/Digital
o Audio FFMpeg/OSS/Analog
o Alsa HDMI/SPDIF Passthrough
o planned: OSS HDMI/SPDIF Passthrough
o planned: atmo light support
To compile you must have the 'requires' installed.
@@ -61,7 +64,7 @@ Install:
http://projects.vdr-developer.org/projects/plg-softhddevice/files
tar vxf vdr-softhddevice-*.tar.bz2
cd vdr-softhddevice
cd softhddevice-*
make VDRDIR=<path-to-your-vdr-files> LIBDIR=.
You can edit Makefile to enable/disable VDPAU / VA-API / Alsa / OSS
@@ -76,6 +79,8 @@ Setup: environment
only if alsa is configured
ALSA_DEVICE=default
alsa PCM device name
ALSA_AC3_DEVICE=
alsa AC3/pass-though device name
ALSA_MIXER=default
alsa control device name
ALSA_MIXER_CHANNEL=PCM
@@ -83,6 +88,8 @@ Setup: environment
only if oss is configured
OSS_AUDIODEV=/dev/dsp
oss dsp device name
OSS_AC3_AUDIODEV=
oss AC3/pass-though device name
OSS_MIXERDEV=/dev/mixer
oss mixer device name
OSS_MIXER_CHANNEL=pcm
@@ -125,6 +132,28 @@ Setup: /etc/vdr/setup.conf
softhddevice.AudioPassthrough = 0
0 = none, 1 = AC-3
for AC-3 the pass-through device is used.
softhddevice.AutoCrop.Interval = 0
0 disables auto-crop
n each 'n' frames auto-crop is checked.
softhddevice.AutoCrop.Delay = 0
if auto-crop is over 'n' intervals the same, the cropping is
used.
softhddevice.AutoCrop.Tolerance = 0
if detected crop area is too small, cut max 'n' pixels at top and
bottom.
softhddevice.Suspend.Close = 0
1 suspend closes x11 window, connection and audio device.
(use svdrpsend plug softhddevice RESU to resume, if you have no lirc)
softhddevice.Suspend.X11 = 0
1 suspend stops X11 server (not working yet)
Setup: /etc/vdr/remote.conf
------
@@ -144,7 +173,22 @@ Setup: /etc/vdr/remote.conf
Commandline:
------------
Use vdr -h to see the command line arguments support by the plugin.
Use vdr -h to see the command line arguments supported by the plugin.
-a audio_device
Selects audio output module and device.
"" to disable audio output
/... to use oss audio module (if compiled with oss
support)
other to use alsa audio module (if compiled with alsa
support)
SVDRP:
------
Use 'svdrpsend.pl plug softhddevice HELP' to see the SVDRP commands
help and which are supported by the plugin.
Running:
--------

74
Todo
View File

@@ -19,58 +19,69 @@ GNU Affero General Public License for more details.
$Id: $
missing:
software deinterlace
auto crop
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 audio, stop video, configurable
suspend output / energie saver: stop and restart X11
Option deinterlace off / deinterlace force!
Make output drivers better moduluar.
Make output drivers better modular (under construction).
crash:
AudioPlayHandlerThread -> pthread_cond_wait
video:
subtitle not cleared
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.
vdpau:
1080i with temporal spatial and level 1 scaling too slow with my GT 520
1080i with temporal spatial too slow with my GT 520 on some channels
SkipChromaDeinterlace improves performance
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
yaepghd (VaapiSetOutputPosition) support
can associate only displayed part of osd
grab image for va-api
still many:
[drm:i915_hangcheck_elapsed] *ERROR* Hangcheck timer elapsed... GPU hung
[drm:i915_wait_request] *ERROR* i915_wait_request returns -11 ...
libva: branch vaapi-ext
add support for vaapi-ext
libva-intel-driver:
intel still has hangups most with 1080i
1080i does no v-sync (workaround written)
osd has sometimes wrong size (workaround written)
1080i does no v-sync (sometimes correct working with vaapi-ext)
OSD has sometimes wrong size (workaround written)
software decoder needs UV swab
libva-vdpau-driver:
G210 osd update too slow (needs hardware problem workaround)
OSD update is too slow
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
libva-xvba-driver:
with auto-crop OSD has wrong position
x11:
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)
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
audio/alsa:
better downmix of >2 channels on 2 channel hardware
remix support of unsupported sample rates
libav supports only resample of mono to 2 channels
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
@@ -79,7 +90,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
support oss pass-through
playback of recording
pause is not reset, when replay exit
@@ -92,7 +103,11 @@ setup:
Setup 4:3 zoom type
Some setup parameters are not used until restart.
Can a notice be added to the setup menu?
576i, 720p, fake 1080i, 1080i
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)
@@ -102,5 +117,6 @@ future features (not planed for 1.0 - 1.5)
software decoder for xv / opengl
atmolight support
multistream handling
pip support
upmix stereo to AC-3

777
audio.c

File diff suppressed because it is too large Load Diff

11
audio.h
View File

@@ -30,21 +30,20 @@
extern void AudioEnqueue(const void *, int); ///< buffer audio samples
extern void AudioFlushBuffers(void); ///< flush audio buffers
extern void AudioPoller(void); ///< poll audio events/handling
extern int AudioFreeBytes(void); ///< free bytes in audio output
//extern int AudioUsedBytes(void); ///< used bytes in audio output
extern uint64_t AudioGetDelay(void); ///< get current audio delay
extern void AudioSetClock(int64_t); ///< set audio clock base
extern int64_t AudioGetClock(); ///< get current audio clock
extern uint64_t AudioGetDelay(void); ///< get current audio delay
extern int AudioSetup(int *, int *); ///< setup audio output
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 AudioSetVolume(int); ///< set volume
extern void AudioSetDevice(const char *); ///< set alsa PCM audio device
extern void AudioSetDevice(const char *); ///< set PCM audio device
extern void AudioSetDeviceAC3(const char *); ///< set Passthrough device
extern void AudioInit(void); ///< setup audio module
extern void AudioExit(void); ///< cleanup and exit audio module

42
codec.c
View File

@@ -320,20 +320,30 @@ static void Codec_draw_horiz_band(AVCodecContext * video_ctx,
**
** @param hw_decoder video hardware decoder
**
** @returns private decoder pointer for audio/video decoder.
** @returns private decoder pointer for video decoder.
*/
VideoDecoder *CodecVideoNewDecoder(VideoHwDecoder * hw_decoder)
{
VideoDecoder *decoder;
if (!(decoder = calloc(1, sizeof(*decoder)))) {
Fatal(_("codec: Can't allocate vodeo decoder\n"));
Fatal(_("codec: can't allocate vodeo decoder\n"));
}
decoder->HwDecoder = hw_decoder;
return decoder;
}
/**
** Deallocate a video decoder context.
**
** @param decoder private video decoder
*/
void CodecVideoDelDecoder(VideoDecoder * decoder)
{
free(decoder);
}
/**
** Open video decoder.
**
@@ -347,6 +357,9 @@ void CodecVideoOpen(VideoDecoder * decoder, const char *name, int codec_id)
Debug(3, "codec: using codec %s or ID %#04x\n", name, codec_id);
if (decoder->VideoCtx) {
Error(_("codec: missing close\n"));
}
//
// ffmpeg compatibility hack
//
@@ -548,13 +561,13 @@ void CodecVideoDecode(VideoDecoder * decoder, const AVPacket * avpkt)
video_ctx->frame_number, used);
}
if (used != pkt->size) {
if (used >= 0) {
if (used >= 0 && used < pkt->size) {
// some tv channels, produce this
Debug(4,
"codec: ooops didn't use complete video packet used %d of %d\n",
used, pkt->size);
pkt->data += used;
pkt->size -= used;
pkt->data += used;
goto next_part;
}
Debug(3, "codec: bad frame %d\n", used);
@@ -613,21 +626,29 @@ static char CodecPassthroughAC3; ///< pass ac3 through
/**
** Allocate a new audio decoder context.
**
** @param hw_decoder video hardware decoder
**
** @returns private decoder pointer for audio/video decoder.
** @returns private decoder pointer for audio decoder.
*/
AudioDecoder *CodecAudioNewDecoder(void)
{
AudioDecoder *audio_decoder;
if (!(audio_decoder = calloc(1, sizeof(*audio_decoder)))) {
Fatal(_("codec: Can't allocate audio decoder\n"));
Fatal(_("codec: can't allocate audio decoder\n"));
}
return audio_decoder;
}
/**
** Deallocate an audio decoder context.
**
** @param decoder private audio decoder
*/
void CodecAudioDelDecoder(AudioDecoder * decoder)
{
free(decoder);
}
/**
** Open audio decoder.
**
@@ -794,6 +815,7 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
if (audio_decoder->SampleRate != audio_ctx->sample_rate
|| audio_decoder->Channels != audio_ctx->channels) {
int err;
int isAC3;
if (audio_decoder->ReSample) {
audio_resample_close(audio_decoder->ReSample);
@@ -807,16 +829,18 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
// SPDIF/HDMI passthrough
if (CodecPassthroughAC3 && audio_ctx->codec_id == CODEC_ID_AC3) {
audio_decoder->HwChannels = 2;
isAC3 = 1;
} else
#endif
{
audio_decoder->HwChannels = audio_ctx->channels;
isAC3 = 0;
}
// channels not support?
if ((err =
AudioSetup(&audio_decoder->HwSampleRate,
&audio_decoder->HwChannels))) {
&audio_decoder->HwChannels, isAC3))) {
Debug(3, "codec/audio: resample %dHz *%d -> %dHz *%d\n",
audio_ctx->sample_rate, audio_ctx->channels,
audio_decoder->HwSampleRate,

View File

@@ -40,6 +40,9 @@ typedef struct _audio_decoder_ AudioDecoder;
/// Allocate a new video decoder context.
extern VideoDecoder *CodecVideoNewDecoder(VideoHwDecoder *);
/// Deallocate a video decoder context.
extern void CodecVideoDelDecoder(VideoDecoder *);
/// Open video codec.
extern void CodecVideoOpen(VideoDecoder *, const char *, int);
@@ -55,6 +58,9 @@ extern void CodecVideoFlushBuffers(VideoDecoder *);
/// Allocate a new audio decoder context.
extern AudioDecoder *CodecAudioNewDecoder(void);
/// Deallocate an audio decoder context.
extern void CodecAudioDelDecoder(AudioDecoder *);
/// Open audio codec.
extern void CodecAudioOpen(AudioDecoder *, const char *, int);

2
misc.h
View File

@@ -86,7 +86,7 @@ static inline void Syslog(const int level, const char *format, ...)
/**
** Show fatal error.
*/
#define Fatal(fmt...) do { Error(fmt); exit(-1); } while (0)
#define Fatal(fmt...) do { Error(fmt); abort(); } while (0)
/**
** Show warning.

View File

@@ -39,6 +39,9 @@
#define __USE_GNU
#endif
#include <pthread.h>
#ifdef USE_JPEG
#include <jpeglib.h>
#endif
#include "misc.h"
#include "softhddev.h"
@@ -58,8 +61,6 @@ static char ConfigVdpauDecoder = 1; ///< use vdpau decoder, if possible
#endif
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
@@ -123,6 +124,8 @@ static const uint16_t SampleRateTable[4] = {
** FrameLengthInBytes = (12 * BitRate / SampleRate + Padding) * 4
** Layer II & III:
** FrameLengthInBytes = 144 * BitRate / SampleRate + Padding
**
** @todo sometimes detects wrong position
*/
static int FindAudioSync(const AVPacket * avpkt)
{
@@ -209,15 +212,15 @@ int PlayAudio(const uint8_t * data, int size,
if (VideoFreezed) { // video freezed
return 0;
}
if (SkipAudio || !MyAudioDecoder) { // skip audio
return size;
}
if (NewAudioStream) {
// FIXME: does this clear the audio ringbuffer?
CodecAudioClose(MyAudioDecoder);
AudioCodecID = CODEC_ID_NONE;
NewAudioStream = 0;
}
if (SkipAudio) { // skip audio
return size;
}
// PES header 0x00 0x00 0x01 ID
// ID 0xBD 0xC0-0xCF
@@ -260,27 +263,17 @@ int PlayAudio(const uint8_t * data, int size,
// Syncword - 0x0B77
if (data[0] == 0x0B && data[1] == 0x77) {
if (!MyAudioDecoder) {
MyAudioDecoder = CodecAudioNewDecoder();
AudioCodecID = CODEC_ID_NONE;
}
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 (!MyAudioDecoder) {
MyAudioDecoder = CodecAudioNewDecoder();
AudioCodecID = CODEC_ID_NONE;
}
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;
}
@@ -297,20 +290,17 @@ int PlayAudio(const uint8_t * data, int size,
if (n < 0) {
return osize;
}
if (!MyAudioDecoder) {
MyAudioDecoder = CodecAudioNewDecoder();
}
avpkt->pts = AV_NOPTS_VALUE;
CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_MP2);
AudioCodecID = CODEC_ID_MP2;
data += n;
size -= n;
}
}
// no decoder or codec known
if (!MyAudioDecoder || AudioCodecID == CODEC_ID_NONE) {
return osize;
// no decoder or codec known
if (AudioCodecID == CODEC_ID_NONE) {
return osize;
}
}
avpkt->data = (void *)data;
@@ -347,7 +337,8 @@ void SetVolumeDevice(int volume)
#include <alsa/iatomic.h> // portable atomic_t
uint32_t VideoSwitch; ///< debug video switch ticks
static volatile char NewVideoStream; ///< new video stream
static volatile char NewVideoStream; ///< flag new video stream
static VideoHwDecoder *MyHwDecoder; ///< video hw decoder
static VideoDecoder *MyVideoDecoder; ///< video decoder
static enum CodecID VideoCodecID; ///< current codec id
@@ -361,7 +352,7 @@ static volatile char Usr1Signal; ///< true got usr1 signal
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
atomic_t VideoPacketsFilled; ///< how many of the buffer is used
static volatile char VideoClearBuffers; ///< clear video buffers
static volatile char SkipVideo; ///< skip video
@@ -388,6 +379,7 @@ static void VideoPacketInit(void)
}
atomic_set(&VideoPacketsFilled, 0);
VideoPacketRead = VideoPacketWrite = 0;
}
/**
@@ -460,10 +452,10 @@ static void VideoNextPacket(int codec_id)
avpkt = &VideoPacketRb[VideoPacketWrite];
if (!avpkt->stream_index) { // ignore empty packets
if (codec_id == CODEC_ID_NONE) {
Debug(3, "video: possible stream change loss\n");
if (codec_id != CODEC_ID_NONE) {
return;
}
return;
Debug(3, "video: possible stream change loss\n");
}
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) {
@@ -477,6 +469,7 @@ static void VideoNextPacket(int codec_id)
}
// clear area for decoder, always enough space allocated
memset(avpkt->data + avpkt->stream_index, 0, FF_INPUT_BUFFER_PADDING_SIZE);
avpkt->priv = (void *)(size_t) codec_id;
// advance packet write
@@ -539,8 +532,8 @@ int VideoDecode(void)
CodecVideoClose(MyVideoDecoder);
goto skip;
}
// size can be zero
goto skip;
break;
case CODEC_ID_MPEG2VIDEO:
if (last_codec_id != CODEC_ID_MPEG2VIDEO) {
last_codec_id = CODEC_ID_MPEG2VIDEO;
@@ -592,16 +585,36 @@ static void StartVideo(void)
}
VideoOsdInit();
if (!MyVideoDecoder) {
VideoHwDecoder *hw_decoder;
if ((hw_decoder = VideoNewHwDecoder())) {
MyVideoDecoder = CodecVideoNewDecoder(hw_decoder);
if ((MyHwDecoder = VideoNewHwDecoder())) {
MyVideoDecoder = CodecVideoNewDecoder(MyHwDecoder);
}
VideoCodecID = CODEC_ID_NONE;
}
VideoPacketInit();
}
/**
** Stop video.
*/
static void StopVideo(void)
{
VideoOsdExit();
VideoExit();
if (MyVideoDecoder) {
// FIXME: this can crash, hw decoder released by video exit
CodecVideoClose(MyVideoDecoder);
CodecVideoDelDecoder(MyVideoDecoder);
MyVideoDecoder = NULL;
}
if (MyHwDecoder) {
// done by exit: VideoDelHwDecoder(MyHwDecoder);
MyHwDecoder = NULL;
}
VideoPacketExit();
NewVideoStream = 1;
}
#ifdef DEBUG
/**
@@ -652,6 +665,9 @@ static int ValidateMpeg(const uint8_t * data, int size)
** supports complete packets.
** We buffer here until we receive an complete PES Packet, which
** is no problem, the audio is always far behind us.
** cTsToPes::GetPes splits the packets.
**
** @todo FIXME: combine the 5 ifs at start of the function
*/
int PlayVideo(const uint8_t * data, int size)
{
@@ -695,7 +711,7 @@ int PlayVideo(const uint8_t * data, int size)
Error(_("[softhddev] invalid video packet %d bytes\n"), size);
return size;
}
// FIXME: hack to test results
// buffer full: needed for replay
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) {
return 0;
}
@@ -729,13 +745,15 @@ int PlayVideo(const uint8_t * data, int size)
}
#endif
}
// FIXME: no valid mpeg2/h264 detection yet
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]);
}
// FIXME: no valid mpeg2/h264 detection yet
// FIXME: better skip all zero's >3 && 0x01 0x09 h264, >2 && 0x01 -> mpeg2
// PES_VIDEO_STREAM 0xE0 or PES start code
//(data[6] & 0xC0) != 0x80 ||
if ((!check[0] && !check[1] && check[2] == 0x1)) {
@@ -775,10 +793,15 @@ int PlayVideo(const uint8_t * data, int size)
Debug(3, "video: not detected\n");
return size;
}
if (VideoCodecID == CODEC_ID_MPEG2VIDEO) {
// 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
VideoEnqueue(pts, check, size - 9 - n);
VideoNextPacket(CODEC_ID_MPEG2VIDEO);
return size;
}
}
@@ -788,6 +811,82 @@ int PlayVideo(const uint8_t * data, int size)
return size;
}
#ifdef USE_JPEG
uint8_t *CreateJpeg(uint8_t * image, int raw_size, int *size, int quality,
int width, int height)
{
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
JSAMPROW row_ptr[1];
int row_stride;
uint8_t *outbuf;
long unsigned int outsize;
outbuf = NULL;
outsize = 0;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_mem_dest(&cinfo, &outbuf, &outsize);
cinfo.image_width = width;
cinfo.image_height = height;
cinfo.input_components = raw_size / height / width;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, quality, TRUE);
jpeg_start_compress(&cinfo, TRUE);
row_stride = width * 3;
while (cinfo.next_scanline < cinfo.image_height) {
row_ptr[0] = &image[cinfo.next_scanline * row_stride];
jpeg_write_scanlines(&cinfo, row_ptr, 1);
}
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
*size = outsize;
return outbuf;
}
#endif
/**
** Grabs the currently visible screen image.
**
** @param size size of the returned data
** @param jpeg flag true, create JPEG data
** @param quality JPEG quality
** @param width number of horizontal pixels in the frame
** @param height number of vertical pixels in the frame
*/
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;
raw_size = 0;
image = VideoGrab(&raw_size, &width, &height, 0);
jpg_image = CreateJpeg(image, raw_size, 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"));
}
return VideoGrab(size, &width, &height, 1);
}
//////////////////////////////////////////////////////////////////////////////
/**
@@ -855,18 +954,50 @@ void Freeze(void)
void StillPicture(const uint8_t * data, int size)
{
int i;
static uint8_t seq_end_mpeg[] = { 0x00, 0x00, 0x01, 0xB7 };
static uint8_t seq_end_h264[] = { 0x00, 0x00, 0x00, 0x01, 0x10 };
// must be a PES start code
if (size < 9 || !data || data[0] || data[1] || data[2] != 0x01) {
Error(_("[softhddev] invalid PES video packet\n"));
Error(_("[softhddev] invalid still video packet\n"));
return;
}
Clear(); // flush video buffers
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
// +1 future for deinterlace
for (i = -1; i < (VideoCodecID == CODEC_ID_MPEG2VIDEO ? 3 : 17); ++i) {
PlayVideo(data, size); // reference frames
//if ( 1 ) {
const uint8_t *split;
int n;
// split the I-frame into single pes packets
split = data;
n = size;
do {
int len;
len = (split[4] << 8) + split[5];
if (len > n) {
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));
}
VideoNextPacket(VideoCodecID); // terminate last packet
}
VideoNextPacket(VideoCodecID); // terminate last packet
}
/**
@@ -913,22 +1044,19 @@ int Flush(int timeout)
void GetOsdSize(int *width, int *height, double *aspect)
{
#ifdef DEBUG
static char done;
static int done_width;
static int done_height;
#endif
// FIXME: should be configured!
*width = 1920;
*height = 1080;
//*width = 768;
//*height = 576;
VideoGetOsdSize(width, height);
*aspect = 16.0 / 9.0 / (double)*width * (double)*height;
#ifdef DEBUG
if (!done) {
if (done_width != *width || done_height != *height) {
Debug(3, "[softhddev]%s: %dx%d %g\n", __FUNCTION__, *width, *height,
*aspect);
done = 1;
done_width = *width;
done_height = *height;
}
#endif
}
@@ -946,7 +1074,6 @@ void OsdClose(void)
*/
void OsdDrawARGB(int x, int y, int height, int width, const uint8_t * argb)
{
Resume();
VideoOsdDrawARGB(x, y, height, width, argb);
}
@@ -960,6 +1087,7 @@ static char ConfigStartX11Server; ///< flag start the x11 server
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"
" -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"
@@ -978,10 +1106,13 @@ int ProcessArgs(int argc, char *const argv[])
// Parse arguments.
//
for (;;) {
switch (getopt(argc, argv, "-a:d:fg:x")) {
switch (getopt(argc, argv, "-a:p:d:fg:x")) {
case 'a': // audio device
AudioSetDevice(optarg);
continue;
case 'p': // pass-through audio device
AudioSetDeviceAC3(optarg);
continue;
case 'd': // x11 display name
X11DisplayName = optarg;
continue;
@@ -1117,22 +1248,18 @@ static void StartXServer(void)
*/
void SoftHdDeviceExit(void)
{
// lets hope that vdr does a good thead cleanup
// no it doesn't do a good thread cleanup
if (MyVideoDecoder) {
CodecVideoClose(MyVideoDecoder);
// FIXME: CodecDelVideoDecoder(MyVideoDecoder);
MyVideoDecoder = NULL;
}
// lets hope that vdr does a good thread cleanup
AudioExit();
if (MyAudioDecoder) {
CodecAudioClose(MyAudioDecoder);
// FIXME: CodecDelAudioDecoder(MyAudioDecoder);
CodecAudioDelDecoder(MyAudioDecoder);
MyAudioDecoder = NULL;
}
NewAudioStream = 0;
StopVideo();
VideoOsdExit();
VideoExit();
AudioExit();
CodecExit();
VideoPacketExit();
@@ -1140,8 +1267,34 @@ void SoftHdDeviceExit(void)
Debug(3, "x-setup: Stop x11 server\n");
if (X11ServerPid) {
int waittime;
int timeout;
pid_t wpid;
int status;
kill(X11ServerPid, SIGTERM);
// FIXME: wait for x11 finishing
waittime = 0;
timeout = 500; // 0.5s
// wait for x11 finishing, with timeout
do {
wpid = waitpid(X11ServerPid, &status, WNOHANG);
if (wpid) {
break;
}
if (waittime++ < timeout) {
usleep(1 * 1000);
continue;
}
kill(X11ServerPid, SIGKILL);
} while (waittime < timeout);
if (wpid && WIFEXITED(status)) {
Debug(3, "x-setup: x11 server exited (%d)\n",
WEXITSTATUS(status));
}
if (wpid && WIFSIGNALED(status)) {
Debug(3, "x-setup: x11 server killed (%d)\n",
WTERMSIG(status));
}
}
}
@@ -1157,8 +1310,12 @@ void Start(void)
StartXServer();
}
CodecInit();
// FIXME: AudioInit for HDMI after X11 startup
AudioInit();
MyAudioDecoder = CodecAudioNewDecoder();
AudioCodecID = CODEC_ID_NONE;
if (!ConfigStartX11Server) {
StartVideo();
}
@@ -1191,8 +1348,12 @@ void MainThreadHook(void)
/**
** Suspend plugin.
**
** @param video suspend closes video
** @param audio suspend closes audio
** @param dox11 suspend closes x11 server
*/
void Suspend(void)
void Suspend(int video, int audio, int dox11)
{
pthread_mutex_lock(&SuspendLockMutex);
if (SkipVideo && SkipAudio) { // already suspended
@@ -1206,13 +1367,25 @@ void Suspend(void)
SkipAudio = 1;
pthread_mutex_unlock(&SuspendLockMutex);
if (ConfigSuspendClose) {
if (audio || video) {
pthread_mutex_lock(&SuspendLockMutex);
// FIXME: close audio
// FIXME: close video
if (audio) {
AudioExit();
if (MyAudioDecoder) {
CodecAudioClose(MyAudioDecoder);
CodecAudioDelDecoder(MyAudioDecoder);
MyAudioDecoder = NULL;
}
NewAudioStream = 0;
}
if (video) {
StopVideo();
}
pthread_mutex_unlock(&SuspendLockMutex);
}
if (ConfigSuspendX11) {
if (dox11) {
// FIXME: stop x11, if started
}
}
@@ -1228,13 +1401,20 @@ void Resume(void)
Debug(3, "[softhddev]%s:\n", __FUNCTION__);
if (ConfigSuspendX11) {
pthread_mutex_lock(&SuspendLockMutex);
// FIXME: start x11
if (!MyHwDecoder) { // video not running
StartVideo();
}
if (ConfigSuspendClose) {
pthread_mutex_lock(&SuspendLockMutex);
pthread_mutex_unlock(&SuspendLockMutex);
if (!MyAudioDecoder) { // audio not running
AudioInit();
MyAudioDecoder = CodecAudioNewDecoder();
AudioCodecID = CODEC_ID_NONE;
}
SkipVideo = 0;
SkipAudio = 0;
pthread_mutex_unlock(&SuspendLockMutex);
}

View File

@@ -46,6 +46,8 @@ extern "C"
extern int PlayVideo(const uint8_t *, int);
/// C plugin play TS video packet
extern void PlayTsVideo(const uint8_t *, int);
/// C plugin grab an image
extern uint8_t *GrabImage(int *, int, int, int, int);
/// C plugin set play mode
extern void SetPlayMode(void);
@@ -77,7 +79,7 @@ extern "C"
extern void MainThreadHook(void);
/// Suspend plugin
extern void Suspend(void);
extern void Suspend(int, int, int);
/// Resume plugin
extern void Resume(void);
#ifdef __cplusplus

View File

@@ -42,7 +42,7 @@ extern "C"
//////////////////////////////////////////////////////////////////////////////
static const char *const VERSION = "0.3.1";
static const char *const VERSION = "0.4.5";
static const char *const DESCRIPTION =
trNOOP("A software and GPU emulated HD device");
@@ -53,6 +53,7 @@ static class cSoftHdDevice *MyDevice;
#define RESOLUTIONS 4 ///< number of resolutions
/// resolutions names
static const char *const Resolution[RESOLUTIONS] = {
"576i", "720p", "1080i_fake", "1080i"
};
@@ -76,8 +77,16 @@ 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
static int ConfigAutoCropDelay; ///< auto crop detection delay
static int ConfigAutoCropTolerance; ///< auto crop detection tolerance
static char ConfigSuspendClose; ///< suspend should close devices
static char ConfigSuspendX11; ///< suspend should stop x11
static volatile char DoMakePrimary; ///< flag switch primary
//////////////////////////////////////////////////////////////////////////////
@@ -122,7 +131,7 @@ extern "C" void FeedKeyPress(const char *keymap, const char *key, int repeat,
csoft = new cSoftRemote(keymap);
}
dsyslog("[softhddev]%s %s, %s\n", __FUNCTION__, keymap, key);
//dsyslog("[softhddev]%s %s, %s\n", __FUNCTION__, keymap, key);
csoft->Put(key, repeat, release);
}
@@ -144,12 +153,13 @@ class cSoftOsd:public cOsd
cSoftOsd::cSoftOsd(int left, int top, uint level)
:cOsd(left, top, level)
{
// FIXME: OsdWidth/OsdHeight not correct!
dsyslog("[softhddev]%s: %dx%d+%d+%d, %d\n", __FUNCTION__, OsdWidth(),
OsdHeight(), left, top, level);
/* FIXME: OsdWidth/OsdHeight not correct!
dsyslog("[softhddev]%s: %dx%d+%d+%d, %d\n", __FUNCTION__, OsdWidth(),
OsdHeight(), left, top, level);
*/
this->Level = level;
//SetActive(true);
SetActive(true);
}
cSoftOsd::~cSoftOsd(void)
@@ -158,8 +168,15 @@ cSoftOsd::~cSoftOsd(void)
SetActive(false);
#ifdef USE_YAEPG
if (vidWin.bpp) {
VideoSetOutputPosition(0, 0, 1920, 1080);
// support yaepghd, video window
if (vidWin.bpp) { // restore fullsized video
int width;
int height;
double video_aspect;
::GetOsdSize(&width, &height, &video_aspect);
// works osd relative
VideoSetOutputPosition(0, 0, width, height);
}
#endif
OsdClose();
@@ -175,8 +192,8 @@ void cSoftOsd::Flush(void)
if (!Active()) {
return;
}
// support yaepghd, video window
#ifdef USE_YAEPG
// support yaepghd, video window
if (vidWin.bpp) {
dsyslog("[softhddev]%s: %dx%d+%d+%d\n", __FUNCTION__, vidWin.Width(),
vidWin.Height(), vidWin.x1, vidWin.y2);
@@ -213,6 +230,7 @@ void cSoftOsd::Flush(void)
if (!bitmap->Dirty(x1, y1, x2, y2)) {
continue; // nothing dirty continue
}
#if 0
// FIXME: need only to convert and upload dirty areas
// DrawBitmap(bitmap);
@@ -225,7 +243,6 @@ void cSoftOsd::Flush(void)
((uint32_t *) argb)[x + y * w] = bitmap->GetColor(x, y);
}
}
// check if subtitles
if (this->Level == OSD_LEVEL_SUBTITLES) {
int video_width;
@@ -238,12 +255,32 @@ void cSoftOsd::Flush(void)
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);
1080 - video_height + Top() + bitmap->Y0(), w, h, argb);
} else {
OsdDrawARGB(Left() + bitmap->X0(), Top() + bitmap->Y0(),
bitmap->Width(), bitmap->Height(), argb);
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;
#ifdef DEBUG
if (w > bitmap->Width() || h > bitmap->Height()) {
esyslog(tr("softhdev: dirty area too big\n"));
abort();
}
#endif
argb = (uint8_t *) malloc(w * h * sizeof(uint32_t));
for (y = y1; y <= y2; ++y) {
for (x = x1; x <= x2; ++x) {
((uint32_t *) argb)[x - x1 + (y - y1) * w] =
bitmap->GetColor(x, y);
}
}
// check if subtitles
OsdDrawARGB(Left() + bitmap->X0() + x1, Top() + bitmap->Y0() + y1,
w, h, argb);
#endif
bitmap->Clean();
free(argb);
@@ -264,8 +301,8 @@ void cSoftOsd::Flush(void)
h = pm->ViewPort().Height();
/*
dsyslog("[softhddev]%s: draw %dx%d+%d+%d %p\n", __FUNCTION__, w, h, x,
y, pm->Data());
dsyslog("[softhddev]%s: draw %dx%d+%d+%d %p\n", __FUNCTION__, w, h,
x, y, pm->Data());
*/
OsdDrawARGB(x, y, w, h, pm->Data());
@@ -334,6 +371,11 @@ class cMenuSetupSoft:public cMenuSetupPage
int Sharpen[RESOLUTIONS];
int AudioDelay;
int AudioPassthrough;
int AutoCropInterval;
int AutoCropDelay;
int AutoCropTolerance;
int SuspendClose;
int SuspendX11;
protected:
virtual void Store(void);
public:
@@ -342,6 +384,8 @@ class cMenuSetupSoft:public cMenuSetupPage
/**
** Create a seperator item.
**
** @param label text inside separator
*/
static inline cOsdItem *SeparatorItem(const char *label)
{
@@ -376,10 +420,10 @@ cMenuSetupSoft::cMenuSetupSoft(void)
// cMenuEditStrItem cMenuEditStraItem cMenuEditIntItem
MakePrimary = ConfigMakePrimary;
Add(new cMenuEditBoolItem(tr("Make primary device"), &MakePrimary,
tr("no"), tr("yes")));
trVDR("no"), trVDR("yes")));
HideMainMenuEntry = ConfigHideMainMenuEntry;
Add(new cMenuEditBoolItem(tr("Hide main menu entry"), &HideMainMenuEntry,
tr("no"), tr("yes")));
trVDR("no"), trVDR("yes")));
//
// video
//
@@ -393,7 +437,7 @@ cMenuSetupSoft::cMenuSetupSoft(void)
deinterlace));
SkipChromaDeinterlace[i] = ConfigVideoSkipChromaDeinterlace[i];
Add(new cMenuEditBoolItem(tr("SkipChromaDeinterlace (vdpau)"),
&SkipChromaDeinterlace[i], tr("no"), tr("yes")));
&SkipChromaDeinterlace[i], trVDR("no"), trVDR("yes")));
Denoise[i] = ConfigVideoDenoise[i];
Add(new cMenuEditIntItem(tr("Denoise (0..1000) (vdpau)"), &Denoise[i],
0, 1000));
@@ -411,6 +455,29 @@ cMenuSetupSoft::cMenuSetupSoft(void)
AudioPassthrough = ConfigAudioPassthrough;
Add(new cMenuEditStraItem(tr("Audio pass-through"), &AudioPassthrough, 2,
passthrough));
//
// auto-crop
//
Add(SeparatorItem(tr("Auto-crop")));
AutoCropInterval = ConfigAutoCropInterval;
Add(new cMenuEditIntItem(tr("autocrop interval (frames)"),
&AutoCropInterval, 0, 200));
AutoCropDelay = ConfigAutoCropDelay;
Add(new cMenuEditIntItem(tr("autocrop delay (n * interval)"),
&AutoCropDelay, 0, 200));
AutoCropTolerance = ConfigAutoCropTolerance;
Add(new cMenuEditIntItem(tr("autocrop tolerance (pixel)"),
&AutoCropTolerance, 0, 32));
//
// suspend
//
Add(SeparatorItem(tr("Suspend")));
SuspendClose = ConfigSuspendClose;
Add(new cMenuEditBoolItem(tr("suspend closes video+audio"), &SuspendClose,
trVDR("no"), trVDR("yes")));
SuspendX11 = ConfigSuspendX11;
Add(new cMenuEditBoolItem(tr("suspend stops x11"), &SuspendX11,
trVDR("no"), trVDR("yes")));
}
/**
@@ -450,6 +517,89 @@ void cMenuSetupSoft::Store(void)
VideoSetAudioDelay(ConfigVideoAudioDelay);
SetupStore("AudioPassthrough", ConfigAudioPassthrough = AudioPassthrough);
CodecSetAudioPassthrough(ConfigAudioPassthrough);
SetupStore("AutoCrop.Interval", ConfigAutoCropInterval = AutoCropInterval);
SetupStore("AutoCrop.Delay", ConfigAutoCropDelay = AutoCropDelay);
SetupStore("AutoCrop.Tolerance", ConfigAutoCropTolerance = AutoCropTolerance);
VideoSetAutoCrop(ConfigAutoCropInterval, ConfigAutoCropDelay, ConfigAutoCropTolerance);
SetupStore("Suspend.Close", ConfigSuspendClose = SuspendClose);
SetupStore("Suspend.X11", ConfigSuspendX11 = SuspendX11);
}
//////////////////////////////////////////////////////////////////////////////
// cPlayer
//////////////////////////////////////////////////////////////////////////////
/**
** Dummy player for suspend mode.
*/
class cSoftHdPlayer:public cPlayer
{
protected:
public:
cSoftHdPlayer(void);
virtual ~ cSoftHdPlayer();
};
cSoftHdPlayer::cSoftHdPlayer(void)
{
}
cSoftHdPlayer::~cSoftHdPlayer()
{
Detach();
}
//////////////////////////////////////////////////////////////////////////////
// cControl
//////////////////////////////////////////////////////////////////////////////
/**
** Dummy control for suspend mode.
*/
class cSoftHdControl:public cControl
{
private:
cSoftHdPlayer * Player;
public:
virtual void Hide(void)
{
}
virtual eOSState ProcessKey(eKeys);
cSoftHdControl(void);
virtual ~ cSoftHdControl();
};
eOSState cSoftHdControl::ProcessKey(eKeys key)
{
if (!ISMODELESSKEY(key) || key == kBack || key == kStop) {
if (Player) {
delete Player;
Player = NULL;
Resume();
}
return osEnd;
}
return osContinue;
}
cSoftHdControl::cSoftHdControl(void)
: cControl(Player = new cSoftHdPlayer)
{
}
cSoftHdControl::~cSoftHdControl()
{
if (Player) {
delete Player;
Player = NULL;
}
Resume();
}
//////////////////////////////////////////////////////////////////////////////
@@ -460,7 +610,7 @@ class cSoftHdDevice:public cDevice
{
public:
cSoftHdDevice(void);
virtual ~ cSoftHdDevice(void);
virtual ~ cSoftHdDevice(void);
virtual bool HasDecoder(void) const;
virtual bool CanReplay(void) const;
@@ -475,17 +625,12 @@ 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 GetVideoSize(int &, int &, double &);
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
#ifndef USE_AUDIO_THREAD // FIXME: testing none threaded
virtual int PlayTsAudio(const uchar *, int);
#endif
virtual void SetAudioChannelDevice(int);
@@ -498,18 +643,16 @@ class cSoftHdDevice:public cDevice
virtual uchar *GrabImage(int &, bool, int, int, int);
virtual int ProvidesCa(const cChannel *) const;
#if 0
// SPU facilities
private:
cDvbSpuDecoder * spuDecoder;
cDvbSpuDecoder * spuDecoder;
public:
virtual cSpuDecoder * GetSpuDecoder(void);
virtual cSpuDecoder * GetSpuDecoder(void);
#endif
protected:
virtual void MakePrimaryDevice(bool);
virtual void MakePrimaryDevice(bool);
};
cSoftHdDevice::cSoftHdDevice(void)
@@ -526,6 +669,11 @@ cSoftHdDevice::~cSoftHdDevice(void)
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
}
/**
** Informs a device that it will be the primary device.
**
** @param on flag if becoming or loosing primary
*/
void cSoftHdDevice::MakePrimaryDevice(bool on)
{
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, on);
@@ -536,18 +684,9 @@ void cSoftHdDevice::MakePrimaryDevice(bool on)
}
}
int cSoftHdDevice::ProvidesCa(
__attribute__ ((unused)) const cChannel *
channel) const
{
//dsyslog("[softhddev]%s: %p\n", __FUNCTION__, channel);
return 0;
}
#if 0
cSpuDecoder *cSoftHdDevice::GetSpuDecoder(void)
cSpuDecoder *cSoftHdDevice::GetSpuDecoder(void)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
@@ -564,16 +703,22 @@ bool cSoftHdDevice::HasDecoder(void) const
return true;
}
/**
** Returns true if this device can currently start a replay session.
*/
bool cSoftHdDevice::CanReplay(void) const
{
return true;
}
bool cSoftHdDevice::SetPlayMode(ePlayMode PlayMode)
/**
** Sets the device into the given play mode.
*/
bool cSoftHdDevice::SetPlayMode(ePlayMode play_mode)
{
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, PlayMode);
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, play_mode);
switch (PlayMode) {
switch (play_mode) {
case pmAudioVideo:
break;
case pmAudioOnly:
@@ -584,9 +729,11 @@ bool cSoftHdDevice::SetPlayMode(ePlayMode PlayMode)
case pmNone:
return true;
case pmExtern_THIS_SHOULD_BE_AVOIDED:
break;
dsyslog("[softhddev] play mode external\n");
Suspend(1, 1, 0);
return true;
default:
dsyslog("[softhddev]playmode not implemented... %d\n", PlayMode);
dsyslog("[softhddev]playmode not implemented... %d\n", play_mode);
break;
}
::SetPlayMode();
@@ -595,7 +742,7 @@ bool cSoftHdDevice::SetPlayMode(ePlayMode PlayMode)
int64_t cSoftHdDevice::GetSTC(void)
{
// dsyslog("[softhddev]%s:\n", __FUNCTION__);
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
return::VideoGetClock();
}
@@ -657,8 +804,8 @@ void cSoftHdDevice::SetVolumeDevice(int volume)
*/
void cSoftHdDevice::StillPicture(const uchar * data, int length)
{
dsyslog("[softhddev]%s: %s\n", __FUNCTION__,
data[0] == 0x47 ? "ts" : "pes");
dsyslog("[softhddev]%s: %s %p %d\n", __FUNCTION__,
data[0] == 0x47 ? "ts" : "pes", data, length);
if (data[0] == 0x47) { // ts sync
cDevice::StillPicture(data, length);
@@ -677,7 +824,7 @@ void cSoftHdDevice::StillPicture(const uchar * data, int length)
bool cSoftHdDevice::Poll(
__attribute__ ((unused)) cPoller & poller, int timeout_ms)
{
// dsyslog("[softhddev]%s: %d\n", __FUNCTION__, timeout_ms);
//dsyslog("[softhddev]%s: %d\n", __FUNCTION__, timeout_ms);
return::Poll(timeout_ms);
}
@@ -697,7 +844,18 @@ bool cSoftHdDevice::Flush(int timeout_ms)
// ----------------------------------------------------------------------------
/**
** Returns the With, Height and PixelAspect ratio the OSD.
** Returns the width, height and video_aspect ratio of the currently
** displayed video material.
**
** @note the size is used to scale the subtitle.
*/
void cSoftHdDevice::GetVideoSize(int &width, int &height, double &video_aspect)
{
::GetOsdSize(&width, &height, &video_aspect);
}
/**
** Returns the width, height and pixel_aspect ratio the OSD.
**
** FIXME: Called every second, for nothing (no OSD displayed)?
*/
@@ -757,33 +915,47 @@ int cSoftHdDevice::PlayVideo(const uchar * data, int length)
///
/// Play a TS video packet.
///
int cSoftHdDevice::PlayTsVideo(const uchar * Data, int Length)
int cSoftHdDevice::PlayTsVideo(const uchar * data, int length)
{
// many code to repeat
}
#endif
#ifdef USE_OSS // FIXME: testing only oss
#ifndef USE_AUDIO_THREAD // FIXME: testing none threaded
///
/// Play a TS audio packet.
///
/// misuse this function as audio poller
///
/// @param data ts data buffer
/// @param length ts packet length
///
int cSoftHdDevice::PlayTsAudio(const uchar * data, int length)
{
AudioPoller();
return cDevice::PlayTsAudio(data, length);
}
#endif
uchar *cSoftHdDevice::GrabImage(int &size, bool jpeg, int quality, int sizex,
int sizey)
/**
** Grabs the currently visible screen image.
**
** @param size size of the returned data
** @param jpeg flag true, create JPEG data
** @param quality JPEG quality
** @param width number of horizontal pixels in the frame
** @param height number of vertical pixels in the frame
*/
uchar *cSoftHdDevice::GrabImage(int &size, bool jpeg, int quality, int width,
int height)
{
dsyslog("[softhddev]%s: %d, %d, %d, %dx%d\n", __FUNCTION__, size, jpeg,
quality, sizex, sizey);
quality, width, height);
return NULL;
return::GrabImage(&size, jpeg, quality, width, height);
}
//////////////////////////////////////////////////////////////////////////////
@@ -802,7 +974,7 @@ class cPluginSoftHdDevice:public cPlugin
virtual bool Initialize(void);
virtual bool Start(void);
virtual void Stop(void);
// virtual void Housekeeping(void);
// virtual void Housekeeping(void);
virtual void MainThreadHook(void);
virtual const char *MainMenuEntry(void);
virtual cOsdObject *MainMenuAction(void);
@@ -901,9 +1073,14 @@ void cPluginSoftHdDevice::Stop(void)
#if 0
/**
** Perform any cleanup or other regular tasks.
*/
void cPluginSoftHdDevice::Housekeeping(void)
{
// Perform any cleanup or other regular tasks.
dsyslog("[softhddev]%s:\n", __FUNCTION__);
// ::Housekeeping();
}
#endif
@@ -923,11 +1100,16 @@ const char *cPluginSoftHdDevice::MainMenuEntry(void)
*/
cOsdObject *cPluginSoftHdDevice::MainMenuAction(void)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
cDevice::PrimaryDevice()->StopReplay();
Suspend();
ShutdownHandler.SetUserInactive();
//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();
}
return NULL;
}
@@ -948,7 +1130,7 @@ void cPluginSoftHdDevice::MainThreadHook(void)
// check if user is inactive, automatic enter suspend mode
if (ShutdownHandler.IsUserInactive()) {
// this is regular called, but guarded against double calls
Suspend();
Suspend(ConfigSuspendClose, ConfigSuspendClose, ConfigSuspendX11);
}
::MainThreadHook();
@@ -966,11 +1148,15 @@ cMenuSetupPage *cPluginSoftHdDevice::SetupMenu(void)
/**
** Parse setup parameters
**
** @param name paramter name (case sensetive)
** @param value value as string
**
** @returns true if the parameter is supported.
*/
bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
{
int i;
char buf[128];
//dsyslog("[softhddev]%s: '%s' = '%s'\n", __FUNCTION__, name, value);
@@ -983,6 +1169,8 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
return true;
}
for (i = 0; i < RESOLUTIONS; ++i) {
char buf[128];
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Scaling");
if (!strcmp(name, buf)) {
ConfigVideoScaling[i] = atoi(value);
@@ -1015,6 +1203,11 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
return true;
}
}
if (!strcmp(name, "SkipLines")) {
VideoSetSkipLines(ConfigVideoSkipLines = atoi(value));
return true;
}
if (!strcmp(name, "AudioDelay")) {
VideoSetAudioDelay(ConfigVideoAudioDelay = atoi(value));
return true;
@@ -1024,6 +1217,29 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
return true;
}
if (!strcmp(name, "AutoCrop.Interval")) {
VideoSetAutoCrop(ConfigAutoCropInterval =
atoi(value), ConfigAutoCropDelay, ConfigAutoCropTolerance);
return true;
}
if (!strcmp(name, "AutoCrop.Delay")) {
VideoSetAutoCrop(ConfigAutoCropInterval, ConfigAutoCropDelay =
atoi(value), ConfigAutoCropTolerance);
return true;
}
if (!strcmp(name, "AutoCrop.Tolerance")) {
VideoSetAutoCrop(ConfigAutoCropInterval, ConfigAutoCropDelay, ConfigAutoCropTolerance = atoi(value));
return true;
}
if (!strcmp(name, "Suspend.Close")) {
ConfigSuspendClose = atoi(value);
return true;
}
if (!strcmp(name, "Suspend.X11")) {
ConfigSuspendX11 = atoi(value);
return true;
}
return false;
}
@@ -1052,8 +1268,10 @@ const char **cPluginSoftHdDevice::SVDRPHelpPages(void)
{
// FIXME: translation?
static const char *text[] = {
"SUSP\n",
" Suspend plugin",
"SUSP\n"
" Suspend plugin.\n",
"RESU\n"
" Resume plugin.\n",
NULL
};
@@ -1068,9 +1286,19 @@ cString cPluginSoftHdDevice::SVDRPCommand(const char *command,
__attribute__ ((unused)) int &reply_code)
{
if (!strcasecmp(command, "SUSP")) {
Suspend();
cControl::Launch(new cSoftHdControl);
cControl::Attach();
Suspend(ConfigSuspendClose, ConfigSuspendClose, ConfigSuspendX11);
return "SoftHdDevice is suspended";
}
if (!strcasecmp(command, "RESU")) {
if (ShutdownHandler.GetUserInactiveTime()) {
ShutdownHandler.SetUserInactiveTimeout();
}
Resume();
cControl::Shutdown(); // not need, if not suspended
return "SoftHdDevice is resumed";
}
return NULL;
}

View File

@@ -21,15 +21,15 @@ SRC_URI=""
LICENSE="AGPL-3"
SLOT="0"
KEYWORDS="~x86 ~amd64"
IUSE="vaapi vdpau alsa oss yaepg"
IUSE="vaapi vdpau alsa oss yaepg opengl jpeg"
DEPEND=">=x11-libs/libxcb-1.7
x11-libs/xcb-util
x11-libs/xcb-util-wm
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
sys-devel/gettext
sys-devel/make
@@ -39,6 +39,8 @@ DEPEND=">=x11-libs/libxcb-1.7
vdpau? ( x11-libs/libvdpau )
vaapi? ( x11-libs/libva )
alsa? ( media-libs/alsa-lib )
oss? ( sys-kernel/linux-headers )
jpeg? ( virtual/jpeg )
"
src_prepare() {
@@ -48,11 +50,12 @@ src_prepare() {
src_compile() {
local myconf
myconf=""
myconf="-DHAVE_PTHREAD_NAME"
use vdpau && myconf="${myconf} -DUSE_VDPAU"
use vaapi && myconf="${myconf} -DUSE_VAAPI"
use alsa && myconf="${myconf} -DUSE_ALSA"
use oss && myconf="${myconf} -DUSE_OSS"
use jpeg && myconf="${myconf} -DUSE_JPEG"
emake all CC="$(tc-getCC)" CFLAGS="${CFLAGS}" \
LDFLAGS="${LDFLAGS}" CONFIG="${myconf}" LIBDIR="." || die

2982
video.c

File diff suppressed because it is too large Load Diff

15
video.h
View File

@@ -37,6 +37,9 @@ typedef struct _video_hw_decoder_ VideoHwDecoder;
/// Allocate new video hardware decoder.
extern VideoHwDecoder *VideoNewHwDecoder(void);
/// Deallocate video hardware decoder.
extern void VideoDelHwDecoder(VideoHwDecoder *);
/// Get and allocate a video hardware surface.
extern unsigned VideoGetSurface(VideoHwDecoder *);
@@ -94,17 +97,29 @@ extern void VideoSetDenoise(int[]);
/// Set sharpen.
extern void VideoSetSharpen(int[]);
/// Set skip lines.
extern void VideoSetSkipLines(int);
/// Set audio delay.
extern void VideoSetAudioDelay(int);
/// Set auto-crop parameters.
extern void VideoSetAutoCrop(int, int, int);
/// Clear OSD.
extern void VideoOsdClear(void);
/// Draw an OSD ARGB image.
extern void VideoOsdDrawARGB(int, int, int, int, const uint8_t *);
/// Get OSD size.
extern void VideoGetOsdSize(int *, int *);
extern int64_t VideoGetClock(void); ///< Get video clock.
/// Grab screen.
extern uint8_t *VideoGrab(int *, int *, int *, int);
extern void VideoOsdInit(void); ///< Setup osd.
extern void VideoOsdExit(void); ///< Cleanup osd.