mirror of
https://github.com/jojo61/vdr-plugin-softhdcuvid.git
synced 2025-03-01 10:39:28 +00:00
Compare commits
57 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
d553a8108d | ||
|
cb4515f6b7 | ||
|
277d7fbd86 | ||
|
9347f2a502 | ||
|
6dfd2d96aa | ||
|
a7471e8800 | ||
|
184cc1aa05 | ||
|
072e1d6847 | ||
|
6c13195fda | ||
|
6a31404aa0 | ||
|
a424a57036 | ||
|
05c2585238 | ||
|
a28e368c1b | ||
|
e4115f348b | ||
|
03b770ce47 | ||
|
c7c4cb06a6 | ||
|
a41f6b22fd | ||
|
628bad5006 | ||
|
cb466dd894 | ||
|
3578e3212d | ||
|
78337f5933 | ||
|
2fea2ee69f | ||
|
c1c345dd4d | ||
|
a3eedbff0c | ||
|
309ad1c90e | ||
|
23651104f2 | ||
|
36c208967e | ||
|
d1a1329beb | ||
|
5875e10479 | ||
|
a6e65d953e | ||
|
fecb81486d | ||
|
f756334187 | ||
|
14ba527a45 | ||
|
ec09dbfb25 | ||
|
34b1fccb28 | ||
|
5586618c6e | ||
|
4dbf2dcc84 | ||
|
74a2285af0 | ||
|
b2bff4ebd0 | ||
|
84501d314e | ||
|
04e1b8732d | ||
|
3e649a5cea | ||
|
feb7479ff8 | ||
|
3590eadbaa | ||
|
6c0f80979f | ||
|
189d8cfa53 | ||
|
73b355c52d | ||
|
3d23288bdc | ||
|
b1a642e64a | ||
|
1b7bfd2087 | ||
|
03e69b5e26 | ||
|
a5b81f8de1 | ||
|
2485929c2b | ||
|
b9fed82109 | ||
|
49db402de6 | ||
|
7ce842b989 | ||
|
9d0417045e |
89
Makefile
89
Makefile
@@ -9,27 +9,31 @@
|
||||
|
||||
|
||||
### Configuration (edit this for your needs)
|
||||
# config as needed
|
||||
# comment out if not needed
|
||||
|
||||
# what kind of decoder do we make -
|
||||
# if VAAPI is enabled the pluginname is softhdvaapi
|
||||
# if CUVID is enabled the pluginname is softhdcuvid
|
||||
# if DRM is enabled the pluginname is softhddrm
|
||||
VAAPI ?= 0
|
||||
CUVID ?= 1
|
||||
CUVID ?= 0
|
||||
|
||||
# if you enable DRM then the plugin will only run without X server
|
||||
# only valid for VAAPI
|
||||
# does not work with libplacebo
|
||||
DRM= ?= 0
|
||||
DRM ?= 0
|
||||
|
||||
|
||||
# use libplacebo - available for both decoders but not for DRM
|
||||
LIBPLACEBO ?= 0
|
||||
# use libplacebo -
|
||||
# available for all decoders but for DRM you need LIBPLACEBO_GL
|
||||
LIBPLACEBO ?= 1
|
||||
LIBPLACEBO_GL ?= 0
|
||||
|
||||
# use YADIF deint - only available with cuvid
|
||||
#YADIF=1
|
||||
|
||||
# use gamma correction
|
||||
#GAMMA ?= 0
|
||||
|
||||
|
||||
|
||||
CONFIG := #-DDEBUG # remove # to enable debug output
|
||||
@@ -39,10 +43,43 @@ CONFIG := #-DDEBUG # remove # to enable debug output
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#--------------------- no more config needed past this point--------------------------------
|
||||
|
||||
# sanitize selections --------
|
||||
ifneq "$(MAKECMDGOALS)" "clean"
|
||||
ifneq "$(MAKECMDGOALS)" "indent"
|
||||
|
||||
ifeq ($(VAAPI),0)
|
||||
ifeq ($(CUVID),0)
|
||||
ifeq ($(DRM),0)
|
||||
$(error Please define a plugin in the Makefile)
|
||||
exit 1;
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
ifeq ($(CUVID),1)
|
||||
ifeq ($(DRM),1)
|
||||
$(error Missmatch in Plugin selection)
|
||||
exit 1;
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
ifeq ($(CUVID),1)
|
||||
ifeq ($(VAAPI),1)
|
||||
$(error Missmatch in Plugin selection)
|
||||
exit 1;
|
||||
endif
|
||||
endif
|
||||
|
||||
endif # MAKECMDGOALS!=indent
|
||||
endif # MAKECMDGOALS!=clean
|
||||
#--------------------------
|
||||
|
||||
|
||||
|
||||
PLUGIN = softhdcuvid
|
||||
|
||||
# support OPENGLOSD always needed
|
||||
@@ -152,19 +189,27 @@ ifeq ($(VAAPI),1)
|
||||
CONFIG += -DVAAPI
|
||||
#LIBPLACEBO=1
|
||||
PLUGIN = softhdvaapi
|
||||
endif
|
||||
|
||||
ifeq ($(LIBPLACEBO_GL),1)
|
||||
CONFIG += -DPLACEBO_GL -DPLACEBO
|
||||
LIBS += -lepoxy
|
||||
LIBS += -lplacebo
|
||||
else
|
||||
LIBS += -lEGL
|
||||
endif
|
||||
|
||||
ifeq ($(LIBPLACEBO),1)
|
||||
CONFIG += -DPLACEBO
|
||||
LIBS += -lEGL
|
||||
LIBS += -lplacebo
|
||||
endif
|
||||
|
||||
ifeq ($(DRM),1)
|
||||
PLUGIN = softhddrm
|
||||
CONFIG += -DUSE_DRM -DVAAPI
|
||||
_CFLAGS += $(shell pkg-config --cflags libdrm)
|
||||
LIBS += -lgbm -ldrm
|
||||
LIBS += -lEGL
|
||||
LIBS += -lgbm -ldrm -lEGL
|
||||
endif
|
||||
|
||||
|
||||
@@ -177,7 +222,9 @@ CONFIG += -DYADIF # Yadif only with CUVID
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
ifeq ($(GAMMA),1)
|
||||
CONFIG += -DGAMMA
|
||||
endif
|
||||
|
||||
|
||||
ARCHIVE = $(PLUGIN)-$(VERSION)
|
||||
@@ -252,18 +299,13 @@ endif
|
||||
_CFLAGS += $(shell pkg-config --cflags x11 x11-xcb xcb xcb-icccm)
|
||||
LIBS += -lrt $(shell pkg-config --libs x11 x11-xcb xcb xcb-icccm)
|
||||
|
||||
_CFLAGS += -I/usr/local/cuda/include
|
||||
_CFLAGS += -I./opengl -I./
|
||||
|
||||
LIBS += -L/usr/lib64
|
||||
LIBS += -L/usr/local/cuda/lib64
|
||||
|
||||
ifeq ($(LIBPLACEBO),1)
|
||||
LIBS += -lplacebo
|
||||
endif
|
||||
|
||||
ifeq ($(CUVID),1)
|
||||
LIBS += -lcuda -L/usr/local/cuda/targets/x86_64-linux/lib -lcudart -lnvcuvid
|
||||
LIBS += -lcuda -lnvcuvid
|
||||
endif
|
||||
|
||||
LIBS += -lGLEW -lGLU -ldl -lglut
|
||||
@@ -284,9 +326,14 @@ override CFLAGS += $(_CFLAGS) $(DEFINES) $(INCLUDES) \
|
||||
|
||||
### The object files (add further files here):
|
||||
|
||||
OBJS = softhdcuvid.o softhddev.o video.o audio.o codec.o ringbuffer.o
|
||||
ifeq ($(OPENGLOSD),1)
|
||||
OBJS += openglosd.o
|
||||
OBJS = softhdcuvid.o softhddev.o video.o audio.o codec.o ringbuffer.o openglosd.o
|
||||
ifeq ($(GAMMA),1)
|
||||
OBJS += colorramp.o
|
||||
ifeq ($(DRM),1)
|
||||
OBJS += gamma-drm.o
|
||||
else
|
||||
OBJS += gamma-vidmode.o
|
||||
endif
|
||||
endif
|
||||
|
||||
SRCS = $(wildcard $(OBJS:.o=.c)) *.cpp
|
||||
|
128
README.md
128
README.md
@@ -23,8 +23,8 @@ $Id: 5267da021a68b4a727b479417334bfbe67bbba14 $
|
||||
|
||||
A software and GPU emulated UHD output device plugin for VDR.
|
||||
|
||||
o Video decoder CPU / VDPAU
|
||||
o Video output opengl
|
||||
o Video decoder CUVID or VAAPI
|
||||
o Video output opengl or DRM
|
||||
o Audio FFMpeg / Alsa / Analog
|
||||
o Audio FFMpeg / Alsa / Digital
|
||||
o Audio FFMpeg / OSS / Analog
|
||||
@@ -32,9 +32,10 @@ A software and GPU emulated UHD output device plugin for VDR.
|
||||
o Software volume, compression, normalize and channel resample
|
||||
o VDR ScaleVideo API
|
||||
o CUDA deinterlacer
|
||||
o Autocrop
|
||||
o Suspend / Dettach
|
||||
o PIP (Picture-in-Picture) (not working yet)
|
||||
o Support for ambilight
|
||||
o Support for Screencopy
|
||||
o PIP (Picture-in-Picture) (only for CUVID)
|
||||
|
||||
|
||||
To compile you must have the 'requires' installed.
|
||||
@@ -47,34 +48,20 @@ Current Status NVIDIA:
|
||||
The CUDA driver supports HEVC with 8 Bit and 10 Bit up to UHD resolution. Opengl is able to output also 10 Bit, but NVIDIA does not support to output 10 Bit via HDMI.
|
||||
Only via DisplayPort you can get 10 Bit output to a compatible screen. This is a restriction from NVIDIA.
|
||||
|
||||
Current Status with VAAPI
|
||||
You need libplacebo.
|
||||
It is still beta and I tested it with Intel VAAPI. If you have problmes with the shaders then copy the drirc file in your home directory as .drirc
|
||||
AMD VAAPI is broken by AMD and will not work currently. The vaapi_deinterlace is broken and the amdgpu driver is instable. I have not testet with amdgpupro
|
||||
Current Status with VAAPI:
|
||||
I tested it with Intel VAAPI. If you have problmes with the shaders then copy the drirc file in your home directory as .drirc
|
||||
AMD VAAPI is broken by AMD and will not work currently.
|
||||
|
||||
You have to adapt the Makefile to your needs. I use FFMPEG 4.0
|
||||
The Makefile expects the CUDA SDK in /usr/local/cuda. Currently it is tested with CUDA 10
|
||||
|
||||
Unfortunatly older FFMEGs has a bug with deinterlacing cuda frames. Best to get the latest FFMPEG Version.
|
||||
|
||||
Otherwise you have to patch the file in libavcodec/cuviddec.c
|
||||
Somewhere near line 860 and 1066 depending on your release:
|
||||
old:
|
||||
ctx->frame_queue = av_fifo_alloc(ctx->nb_surfaces * sizeof(CuvidParsedFrame));
|
||||
|
||||
new:
|
||||
ctx->frame_queue = av_fifo_alloc((ctx->nb_surfaces + 2 ) * sizeof(CuvidParsedFrame));
|
||||
|
||||
This Version supports building with libplacebo. https://github.com/haasn/libplacebo
|
||||
You have to enable it in the Makefile and install libplacebo yourself.
|
||||
At the moment this is Work in progress.
|
||||
|
||||
It also needs the NVIDIA driver 410.48 or newer as well as CUDA 10.
|
||||
|
||||
In the settings you can enable a correction for Colorblindness. First you have to decide what kind of colorblindness to use. And then the faktor of correction. If the faktor is negativ than the selected type of colorblindness is simulated. If the faktor is positiv then the colors are enhanced to try to correct the deficiency.
|
||||
I recommend to use libplacebo. It has much better scaler and does colorconversion for HDR the correct way.
|
||||
|
||||
Also you can enable a Scaler Test feature. When enabled then the screen is split.On the left half you will see the scaler defined by Scaler Test and on the right side you will see the scaler defined at the Resolution setting. There is as small black line between the halfs to remaind you that Scaler Test is activ.
|
||||
|
||||
If your FFMEG supports it then you can enable YADIF in the Makefile and select btween the buildin NVIDIA CUDA deinterlacer and the YADIF cuda deinterlacer.
|
||||
If your FFMEG supports it then you can enable YADIF in the Makefile and select between the buildin NVIDIA CUDA deinterlacer and the YADIF cuda deinterlacer.
|
||||
|
||||
Good luck
|
||||
jojo61
|
||||
@@ -82,7 +69,17 @@ jojo61
|
||||
Quickstart:
|
||||
-----------
|
||||
|
||||
Just type make and use.
|
||||
You have to adapt the Makefile. There are 3 possible Version that you can build:
|
||||
|
||||
softhdcuvid
|
||||
This is for NVIDA cards and uses cuvid as decoder. It uses xcb for output and needs a X Server to run.
|
||||
|
||||
softhdvaapi
|
||||
This is for INTEL cards and uses Vaapi as decoder. It uses xcb for output and needs a X Server to run.
|
||||
|
||||
softhddrm
|
||||
This is for INTEL cards and also uses Vaapi as decoder. It uses the DRM API for output and
|
||||
runs without X Server. There are several commandline options to select the resolution and refresh rate.
|
||||
|
||||
Install:
|
||||
--------
|
||||
@@ -98,6 +95,34 @@ Install:
|
||||
|
||||
You have to start vdr with -P 'softhdcuvid -d :0.0 ..<more option>.. '
|
||||
|
||||
Beginners Guide for libplacebo:
|
||||
-------------------------------
|
||||
When using libplacebo you will find several config options.
|
||||
|
||||
First of all you need to set the right scaler for each resolution:
|
||||
Best you beginn with setting all to "bilinear". If that works ok for you, you can try to change them
|
||||
for more advanced scaler. I use ewa_robidouxsharp on my GTX1050, but your mileage may vary.
|
||||
Unfortunatly on INTEL not all scalers may work or crash.
|
||||
|
||||
You can enable a Scaler Test feature. When enabled then the screen is split.On the left half you will
|
||||
see the scaler defined by Scaler Test and on the right side you will see the scaler defined at the
|
||||
Resolution setting. There is as small black line between the halfs to remaind you that Scaler Test
|
||||
is activ.
|
||||
|
||||
Then you should set the Monitor Colorspace to "sRGB". This guarantees you the best colors on your screen.
|
||||
At the moment all calculations internaly are done in RGB space and all cards output also RGB.
|
||||
|
||||
If you are colorblind you could try to remedy this with the Colorblind Settings. Realy only needed
|
||||
in rare cases.
|
||||
|
||||
All other settings can be in their default state.
|
||||
|
||||
Beginning with libplacebo API 58 user shaders from mpv are supported. Use -S parameter to set the shader.
|
||||
The plugins searches the shaders in $ConfigDir/plugins/shaders for the shaders. One example shader is
|
||||
provided in the shader subdirectory. Copy it to e.g.: /etc/vdr/plugins/shaders and then start
|
||||
vdr -P 'softhdcuvid -S filmgrain.glsl ...'
|
||||
|
||||
|
||||
|
||||
Setup: environment
|
||||
------
|
||||
@@ -211,18 +236,6 @@ Setup: /etc/vdr/setup.conf
|
||||
0 = default (336 ms)
|
||||
1 - 1000 = size of the buffer in ms
|
||||
|
||||
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.Background = 0
|
||||
32bit RGBA background color
|
||||
(Red * 16777216 + Green * 65536 + Blue * 256 + Alpha)
|
||||
@@ -262,11 +275,13 @@ Setup: /etc/vdr/setup.conf
|
||||
0 pan and scan
|
||||
1 letter box
|
||||
2 center cut-out
|
||||
3 original
|
||||
|
||||
softhddevice.VideoOtherDisplayFormat = 1
|
||||
0 pan and scan
|
||||
1 pillar box
|
||||
2 center cut-out
|
||||
3 original
|
||||
|
||||
softhddevice.pip.X = 79
|
||||
softhddevice.pip.Y = 78
|
||||
@@ -293,22 +308,6 @@ Setup: /etc/vdr/setup.conf
|
||||
PIP alternative video window position and size in percent.
|
||||
|
||||
|
||||
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:
|
||||
------------
|
||||
|
||||
@@ -356,25 +355,4 @@ Running:
|
||||
|
||||
Known Bugs:
|
||||
-----------
|
||||
SD Stream not working very well
|
||||
RESUME starts wirh black screen (channelswitch needed)
|
||||
|
||||
Requires:
|
||||
---------
|
||||
media-video/vdr (version >=1.7.xx)
|
||||
Video Disk Recorder - turns a pc into a powerful set top box
|
||||
for DVB.
|
||||
http://www.tvdr.de/
|
||||
|
||||
media-video/ffmpeg (version >=0.7)
|
||||
Complete solution to record, convert and stream audio and
|
||||
video. Includes libavcodec and libswresample.
|
||||
http://ffmpeg.org
|
||||
media-libs/alsa-lib
|
||||
Advanced Linux Sound Architecture Library
|
||||
http://www.alsa-project.org
|
||||
or
|
||||
kernel support for oss/oss4 or alsa oss emulation
|
||||
|
||||
|
||||
Optional:
|
||||
SD Streams not working very well on vaapi
|
||||
|
75
audio.c
75
audio.c
@@ -86,6 +86,8 @@
|
||||
#define __USE_GNU
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/resource.h>
|
||||
#ifndef HAVE_PTHREAD_NAME
|
||||
/// only available with newer glibc
|
||||
#define pthread_setname_np(thread, name)
|
||||
@@ -144,7 +146,6 @@ static volatile char AudioRunning; ///< thread running / stopped
|
||||
static volatile char AudioPaused; ///< audio paused
|
||||
static volatile char AudioVideoIsReady; ///< video ready start early
|
||||
static int AudioSkip; ///< skip audio to sync to video
|
||||
int AudioDelay; /// delay audio to sync to video
|
||||
|
||||
static const int AudioBytesProSample = 2; ///< number of bytes per sample
|
||||
|
||||
@@ -688,7 +689,7 @@ static int AudioRingAdd(unsigned sample_rate, int channels, int passthrough)
|
||||
AudioRing[AudioRingWrite].InChannels = channels;
|
||||
AudioRing[AudioRingWrite].HwSampleRate = sample_rate;
|
||||
AudioRing[AudioRingWrite].HwChannels = AudioChannelMatrix[u][channels];
|
||||
AudioRing[AudioRingWrite].PTS = INT64_C(0x8000000000000000);
|
||||
AudioRing[AudioRingWrite].PTS = AV_NOPTS_VALUE;
|
||||
RingBufferReset(AudioRing[AudioRingWrite].RingBuffer);
|
||||
|
||||
Debug(3, "audio: %d ring buffer prepared\n", atomic_read(&AudioRingFilled) + 1);
|
||||
@@ -1156,7 +1157,7 @@ static int64_t AlsaGetDelay(void)
|
||||
//Debug(3, "audio/alsa: %ld frames delay ok, but not running\n", delay);
|
||||
#endif
|
||||
}
|
||||
//Debug(3, "audio/alsa: %ld frames hw delay\n", delay);
|
||||
Debug(4, "audio/alsa: %ld frames hw delay\n", delay);
|
||||
|
||||
// delay can be negative, when underrun occur
|
||||
if (delay < 0) {
|
||||
@@ -1291,7 +1292,6 @@ static int AlsaSetup(int *freq, int *channels, int passthrough)
|
||||
Info(_("audio/alsa: start delay %ums\n"), (AudioStartThreshold * 1000)
|
||||
/ (*freq * *channels * AudioBytesProSample));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1989,7 +1989,7 @@ static int AudioNextRing(void)
|
||||
|
||||
// stop, if not enough in next buffer
|
||||
used = RingBufferUsedBytes(AudioRing[AudioRingRead].RingBuffer);
|
||||
if (AudioStartThreshold * 10 < used || (AudioVideoIsReady && AudioStartThreshold < used)) {
|
||||
if (AudioStartThreshold * 4 < used || (AudioVideoIsReady && AudioStartThreshold < used)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
@@ -2004,6 +2004,7 @@ static void *AudioPlayHandlerThread(void *dummy)
|
||||
{
|
||||
Debug(3, "audio: play thread started\n");
|
||||
prctl(PR_SET_NAME, "cuvid audio", 0, 0, 0);
|
||||
|
||||
for (;;) {
|
||||
// check if we should stop the thread
|
||||
if (AudioThreadStop) {
|
||||
@@ -2020,9 +2021,10 @@ static void *AudioPlayHandlerThread(void *dummy)
|
||||
} while (!AudioRunning);
|
||||
pthread_mutex_unlock(&AudioMutex);
|
||||
|
||||
Debug(3, "audio: ----> %dms start\n", (AudioUsedBytes() * 1000)
|
||||
Debug(3, "audio: ----> %dms %d start\n", (AudioUsedBytes() * 1000)
|
||||
/ (!AudioRing[AudioRingWrite].HwSampleRate + !AudioRing[AudioRingWrite].HwChannels +
|
||||
AudioRing[AudioRingWrite].HwSampleRate * AudioRing[AudioRingWrite].HwChannels * AudioBytesProSample));
|
||||
AudioRing[AudioRingWrite].HwSampleRate * AudioRing[AudioRingWrite].HwChannels * AudioBytesProSample),
|
||||
AudioUsedBytes());
|
||||
|
||||
do {
|
||||
int filled;
|
||||
@@ -2056,10 +2058,8 @@ static void *AudioPlayHandlerThread(void *dummy)
|
||||
AudioUsedModule->FlushBuffers();
|
||||
atomic_sub(flush, &AudioRingFilled);
|
||||
if (AudioNextRing()) {
|
||||
Debug(3, "audio: HandlerThread break after flush\n");
|
||||
break;
|
||||
}
|
||||
Debug(3, "audio: continue after flush\n");
|
||||
}
|
||||
// try to play some samples
|
||||
err = 0;
|
||||
@@ -2284,18 +2284,18 @@ void AudioEnqueue(const void *samples, int count)
|
||||
}
|
||||
// forced start or enough video + audio buffered
|
||||
// for some exotic channels * 4 too small
|
||||
if (AudioStartThreshold * 10 < n || (AudioVideoIsReady
|
||||
if (AudioStartThreshold * 4 < n || (AudioVideoIsReady
|
||||
// if ((AudioVideoIsReady
|
||||
&& AudioStartThreshold < n)) {
|
||||
// restart play-back
|
||||
// no lock needed, can wakeup next time
|
||||
AudioRunning = 1;
|
||||
pthread_cond_signal(&AudioStartCond);
|
||||
Debug(3, "Start on AudioEnque\n");
|
||||
Debug(3, "Start on AudioEnque Threshold %d n %d\n", AudioStartThreshold, n);
|
||||
}
|
||||
}
|
||||
// Update audio clock (stupid gcc developers thinks INT64_C is unsigned)
|
||||
if (AudioRing[AudioRingWrite].PTS != (int64_t) INT64_C(0x8000000000000000)) {
|
||||
if (AudioRing[AudioRingWrite].PTS != (int64_t) AV_NOPTS_VALUE) {
|
||||
AudioRing[AudioRingWrite].PTS += ((int64_t) count * 90 * 1000)
|
||||
/ (AudioRing[AudioRingWrite].HwSampleRate * AudioRing[AudioRingWrite].HwChannels * AudioBytesProSample);
|
||||
}
|
||||
@@ -2311,13 +2311,13 @@ void AudioVideoReady(int64_t pts)
|
||||
int64_t audio_pts;
|
||||
size_t used;
|
||||
|
||||
if (pts == (int64_t) INT64_C(0x8000000000000000)) {
|
||||
if (pts == (int64_t) AV_NOPTS_VALUE) {
|
||||
Debug(3, "audio: a/v start, no valid video\n");
|
||||
return;
|
||||
}
|
||||
// no valid audio known
|
||||
if (!AudioRing[AudioRingWrite].HwSampleRate || !AudioRing[AudioRingWrite].HwChannels
|
||||
|| AudioRing[AudioRingWrite].PTS == (int64_t) INT64_C(0x8000000000000000)) {
|
||||
|| AudioRing[AudioRingWrite].PTS == (int64_t) AV_NOPTS_VALUE) {
|
||||
Debug(3, "audio: a/v start, no valid audio\n");
|
||||
AudioVideoIsReady = 1;
|
||||
return;
|
||||
@@ -2340,9 +2340,9 @@ void AudioVideoReady(int64_t pts)
|
||||
|
||||
// buffer ~15 video frames
|
||||
// FIXME: HDTV can use smaller video buffer
|
||||
skip = pts - 15 * 20 * 90 - AudioBufferTime * 90 - audio_pts + VideoAudioDelay;
|
||||
skip = pts - 0 * 20 * 90 - AudioBufferTime * 90 - audio_pts + VideoAudioDelay;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "%dms %dms %dms\n", (int)(pts - audio_pts) / 90, VideoAudioDelay / 90, skip / 90);
|
||||
// fprintf(stderr, "a/v-diff %dms a/v-delay %dms skip %dms Audiobuffer %d\n", (int)(pts - audio_pts) / 90, VideoAudioDelay / 90, skip / 90,AudioBufferTime);
|
||||
#endif
|
||||
// guard against old PTS
|
||||
if (skip > 0 && skip < 4000 * 90) {
|
||||
@@ -2353,9 +2353,9 @@ void AudioVideoReady(int64_t pts)
|
||||
AudioSkip = skip - used;
|
||||
skip = used;
|
||||
}
|
||||
Debug(3, "audio: sync advance %dms %d/%zd\n",
|
||||
Debug(3, "audio: sync advance %dms %d/%zd Rest %d\n",
|
||||
(skip * 1000) / (AudioRing[AudioRingWrite].HwSampleRate * AudioRing[AudioRingWrite].HwChannels *
|
||||
AudioBytesProSample), skip, used);
|
||||
AudioBytesProSample), skip, used, AudioSkip);
|
||||
RingBufferReadAdvance(AudioRing[AudioRingWrite].RingBuffer, skip);
|
||||
|
||||
used = RingBufferUsedBytes(AudioRing[AudioRingWrite].RingBuffer);
|
||||
@@ -2363,7 +2363,6 @@ void AudioVideoReady(int64_t pts)
|
||||
Debug(3, "No audio skip -> should skip %d\n", skip / 90);
|
||||
}
|
||||
// FIXME: skip<0 we need bigger audio buffer
|
||||
|
||||
// enough video + audio buffered
|
||||
if (AudioStartThreshold < used) {
|
||||
AudioRunning = 1;
|
||||
@@ -2373,38 +2372,7 @@ void AudioVideoReady(int64_t pts)
|
||||
}
|
||||
|
||||
AudioVideoIsReady = 1;
|
||||
#if 0
|
||||
if (AudioRing[AudioRingWrite].HwSampleRate && AudioRing[AudioRingWrite].HwChannels) {
|
||||
if (pts != (int64_t) INT64_C(0x8000000000000000)
|
||||
&& AudioRing[AudioRingWrite].PTS != (int64_t) INT64_C(0x8000000000000000)) {
|
||||
Debug(3, "audio: a/v %d %s\n", (int)(pts - AudioRing[AudioRingWrite].PTS) / 90,
|
||||
AudioRunning ? "running" : "stopped");
|
||||
}
|
||||
Debug(3, "audio: start %4zdms %s|%s video ready\n",
|
||||
(RingBufferUsedBytes(AudioRing[AudioRingWrite].RingBuffer) * 1000)
|
||||
/ (AudioRing[AudioRingWrite].HwSampleRate * AudioRing[AudioRingWrite].HwChannels * AudioBytesProSample),
|
||||
Timestamp2String(pts), Timestamp2String(AudioRing[AudioRingWrite].PTS));
|
||||
|
||||
if (!AudioRunning) {
|
||||
size_t used;
|
||||
|
||||
used = RingBufferUsedBytes(AudioRing[AudioRingWrite].RingBuffer);
|
||||
// enough video + audio buffered
|
||||
if (AudioStartThreshold < used) {
|
||||
// too much audio buffered, skip it
|
||||
if (AudioStartThreshold < used) {
|
||||
Debug(3, "audio: start %4zdms skip video ready\n", ((used - AudioStartThreshold) * 1000)
|
||||
/ (AudioRing[AudioRingWrite].HwSampleRate * AudioRing[AudioRingWrite].HwChannels *
|
||||
AudioBytesProSample));
|
||||
RingBufferReadAdvance(AudioRing[AudioRingWrite].RingBuffer, used - AudioStartThreshold);
|
||||
}
|
||||
AudioRunning = 1;
|
||||
pthread_cond_signal(&AudioStartCond);
|
||||
}
|
||||
}
|
||||
}
|
||||
AudioVideoIsReady = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2439,7 +2407,7 @@ void AudioFlushBuffers(void)
|
||||
AudioRing[AudioRingWrite].HwChannels = AudioRing[old].HwChannels;
|
||||
AudioRing[AudioRingWrite].InSampleRate = AudioRing[old].InSampleRate;
|
||||
AudioRing[AudioRingWrite].InChannels = AudioRing[old].InChannels;
|
||||
AudioRing[AudioRingWrite].PTS = INT64_C(0x8000000000000000);
|
||||
AudioRing[AudioRingWrite].PTS = AV_NOPTS_VALUE;
|
||||
RingBufferReadAdvance(AudioRing[AudioRingWrite].RingBuffer,
|
||||
RingBufferUsedBytes(AudioRing[AudioRingWrite].RingBuffer));
|
||||
Debug(3, "audio: reset video ready\n");
|
||||
@@ -2529,6 +2497,7 @@ void AudioSetClock(int64_t pts)
|
||||
Debug(4, "audio: set clock %s -> %s pts\n", Timestamp2String(AudioRing[AudioRingWrite].PTS),
|
||||
Timestamp2String(pts));
|
||||
}
|
||||
// printf("Audiosetclock pts %#012" PRIx64 " %d\n",pts,RingBufferUsedBytes(AudioRing[AudioRingWrite].RingBuffer));
|
||||
AudioRing[AudioRingWrite].PTS = pts;
|
||||
}
|
||||
|
||||
@@ -2540,7 +2509,7 @@ void AudioSetClock(int64_t pts)
|
||||
int64_t AudioGetClock(void)
|
||||
{
|
||||
// (cast) needed for the evil gcc
|
||||
if (AudioRing[AudioRingRead].PTS != (int64_t) INT64_C(0x8000000000000000)) {
|
||||
if (AudioRing[AudioRingRead].PTS != (int64_t) AV_NOPTS_VALUE) {
|
||||
int64_t delay;
|
||||
|
||||
// delay zero, if no valid time stamp
|
||||
@@ -2551,7 +2520,7 @@ int64_t AudioGetClock(void)
|
||||
return AudioRing[AudioRingRead].PTS + 0 * 90 - delay;
|
||||
}
|
||||
}
|
||||
return INT64_C(0x8000000000000000);
|
||||
return AV_NOPTS_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
468
codec.c
468
codec.c
@@ -75,9 +75,6 @@
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
|
||||
#ifdef MAIN_H
|
||||
#include MAIN_H
|
||||
#endif
|
||||
#include "iatomic.h"
|
||||
#include "misc.h"
|
||||
#include "video.h"
|
||||
@@ -259,18 +256,18 @@ void CodecVideoOpen(VideoDecoder * decoder, int codec_id)
|
||||
#endif
|
||||
#ifdef RASPI
|
||||
switch (codec_id) {
|
||||
case AV_CODEC_ID_MPEG2VIDEO:
|
||||
name = "mpeg2_v4l2m2m";
|
||||
break;
|
||||
case AV_CODEC_ID_H264:
|
||||
name = "h264_v4l2m2m";
|
||||
case AV_CODEC_ID_MPEG2VIDEO:
|
||||
name = "mpeg2_v4l2m2m";
|
||||
break;
|
||||
case AV_CODEC_ID_H264:
|
||||
name = "h264_v4l2m2m";
|
||||
// name = "h264_mmal";
|
||||
break;
|
||||
case AV_CODEC_ID_HEVC:
|
||||
name = "hevc_v4l2m2m";
|
||||
break;
|
||||
break;
|
||||
case AV_CODEC_ID_HEVC:
|
||||
name = "hevc_v4l2m2m";
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
if (name && (video_codec = avcodec_find_decoder_by_name(name))) {
|
||||
Debug(3, "codec: decoder found\n");
|
||||
} else if ((video_codec = avcodec_find_decoder(codec_id)) == NULL) {
|
||||
@@ -285,15 +282,15 @@ void CodecVideoOpen(VideoDecoder * decoder, int codec_id)
|
||||
if (!(decoder->VideoCtx = avcodec_alloc_context3(video_codec))) {
|
||||
Fatal(_("codec: can't allocate video codec context\n"));
|
||||
}
|
||||
|
||||
|
||||
#ifndef RASPI
|
||||
if (!HwDeviceContext) {
|
||||
Fatal("codec: no hw device context to be used");
|
||||
}
|
||||
decoder->VideoCtx->hw_device_ctx = av_buffer_ref(HwDeviceContext);
|
||||
#else
|
||||
decoder->VideoCtx->pix_fmt = AV_PIX_FMT_DRM_PRIME; /* request a DRM frame
|
||||
// decoder->VideoCtx->pix_fmt = AV_PIX_FMT_MMAL; /* request a DRM frame */
|
||||
decoder->VideoCtx->pix_fmt = AV_PIX_FMT_DRM_PRIME; /* request a DRM frame */
|
||||
// decoder->VideoCtx->pix_fmt = AV_PIX_FMT_MMAL; /* request a DRM frame */
|
||||
#endif
|
||||
|
||||
// FIXME: for software decoder use all cpus, otherwise 1
|
||||
@@ -314,7 +311,7 @@ void CodecVideoOpen(VideoDecoder * decoder, int codec_id)
|
||||
if (video_codec->capabilities & (AV_CODEC_CAP_AUTO_THREADS)) {
|
||||
Debug(3, "codec: auto threads enabled");
|
||||
// decoder->VideoCtx->thread_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (video_codec->capabilities & AV_CODEC_CAP_TRUNCATED) {
|
||||
Debug(3, "codec: supports truncated packets");
|
||||
@@ -337,9 +334,9 @@ void CodecVideoOpen(VideoDecoder * decoder, int codec_id)
|
||||
// if (av_opt_set_int(decoder->VideoCtx, "refcounted_frames", 1, 0) < 0)
|
||||
// Fatal(_("VAAPI Refcounts invalid\n"));
|
||||
decoder->VideoCtx->thread_safe_callbacks = 0;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef RASPI
|
||||
decoder->VideoCtx->codec_id = codec_id;
|
||||
decoder->VideoCtx->flags |= AV_CODEC_FLAG_BITEXACT;
|
||||
@@ -498,7 +495,7 @@ void DisplayPts(AVCodecContext * video_ctx, AVFrame * frame)
|
||||
*/
|
||||
extern int CuvidTestSurfaces();
|
||||
|
||||
#ifdef YADIF
|
||||
#if defined YADIF || defined (VAAPI)
|
||||
extern int init_filters(AVCodecContext * dec_ctx, void *decoder, AVFrame * frame);
|
||||
extern int push_filters(AVCodecContext * dec_ctx, void *decoder, AVFrame * frame);
|
||||
#endif
|
||||
@@ -512,18 +509,18 @@ void CodecVideoDecode(VideoDecoder * decoder, const AVPacket * avpkt)
|
||||
int ret;
|
||||
AVPacket pkt[1];
|
||||
AVFrame *frame;
|
||||
|
||||
|
||||
*pkt = *avpkt; // use copy
|
||||
ret = avcodec_send_packet(video_ctx, pkt);
|
||||
if (ret < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!CuvidTestSurfaces())
|
||||
usleep(1000);
|
||||
|
||||
|
||||
ret = 0;
|
||||
while (ret >= 0 && CuvidTestSurfaces()) {
|
||||
while (ret >= 0 && CuvidTestSurfaces()) {
|
||||
frame = av_frame_alloc();
|
||||
ret = avcodec_receive_frame(video_ctx, frame);
|
||||
|
||||
@@ -553,7 +550,7 @@ void CodecVideoDecode(VideoDecoder * decoder, const AVPacket * avpkt)
|
||||
av_frame_free(&frame);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -600,8 +597,9 @@ void CodecVideoDecode(VideoDecoder * decoder, const AVPacket * avpkt)
|
||||
} else {
|
||||
got_frame = 0;
|
||||
}
|
||||
// printf("got %s packet from decoder\n",got_frame?"1":"no");
|
||||
// printf("got %s packet from decoder\n",got_frame?"1":"no");
|
||||
if (got_frame) { // frame completed
|
||||
// printf("video frame pts %#012" PRIx64 " %dms\n",frame->pts,(int)(apts - frame->pts) / 90);
|
||||
#ifdef YADIF
|
||||
if (decoder->filter) {
|
||||
if (decoder->filter == 1) {
|
||||
@@ -682,9 +680,6 @@ struct _audio_decoder_
|
||||
|
||||
AVFrame *Frame; ///< decoded audio frame buffer
|
||||
|
||||
#if !defined(USE_SWRESAMPLE) && !defined(USE_AVRESAMPLE)
|
||||
ReSampleContext *ReSample; ///< old resampling context
|
||||
#endif
|
||||
#ifdef USE_SWRESAMPLE
|
||||
#if LIBSWRESAMPLE_VERSION_INT < AV_VERSION_INT(0, 15, 100)
|
||||
struct SwrContext *Resample; ///< ffmpeg software resample context
|
||||
@@ -707,16 +702,6 @@ struct _audio_decoder_
|
||||
int Drift; ///< accumulated audio drift
|
||||
int DriftCorr; ///< audio drift correction value
|
||||
int DriftFrac; ///< audio drift fraction for ac3
|
||||
|
||||
#if !defined(USE_SWRESAMPLE) && !defined(USE_AVRESAMPLE)
|
||||
struct AVResampleContext *AvResample; ///< second audio resample context
|
||||
#define MAX_CHANNELS 8 ///< max number of channels supported
|
||||
int16_t *Buffer[MAX_CHANNELS]; ///< deinterleave sample buffers
|
||||
int BufferSize; ///< size of sample buffer
|
||||
int16_t *Remain[MAX_CHANNELS]; ///< filter remaining samples
|
||||
int RemainSize; ///< size of remain buffer
|
||||
int RemainCount; ///< number of remaining samples
|
||||
#endif
|
||||
};
|
||||
|
||||
///
|
||||
@@ -799,7 +784,7 @@ void CodecAudioOpen(AudioDecoder * audio_decoder, int codec_id)
|
||||
}
|
||||
|
||||
if (CodecDownmix) {
|
||||
audio_decoder->AudioCtx->request_channel_layout = AV_CH_LAYOUT_STEREO_DOWNMIX;
|
||||
audio_decoder->AudioCtx->request_channel_layout = AV_CH_LAYOUT_STEREO;
|
||||
}
|
||||
pthread_mutex_lock(&CodecLockMutex);
|
||||
// open codec
|
||||
@@ -835,27 +820,7 @@ void CodecAudioOpen(AudioDecoder * audio_decoder, int codec_id)
|
||||
void CodecAudioClose(AudioDecoder * audio_decoder)
|
||||
{
|
||||
// FIXME: output any buffered data
|
||||
#if !defined(USE_SWRESAMPLE) && !defined(USE_AVRESAMPLE)
|
||||
if (audio_decoder->AvResample) {
|
||||
int ch;
|
||||
|
||||
av_resample_close(audio_decoder->AvResample);
|
||||
audio_decoder->AvResample = NULL;
|
||||
audio_decoder->RemainCount = 0;
|
||||
audio_decoder->BufferSize = 0;
|
||||
audio_decoder->RemainSize = 0;
|
||||
for (ch = 0; ch < MAX_CHANNELS; ++ch) {
|
||||
free(audio_decoder->Buffer[ch]);
|
||||
audio_decoder->Buffer[ch] = NULL;
|
||||
free(audio_decoder->Remain[ch]);
|
||||
audio_decoder->Remain[ch] = NULL;
|
||||
}
|
||||
}
|
||||
if (audio_decoder->ReSample) {
|
||||
audio_resample_close(audio_decoder->ReSample);
|
||||
audio_decoder->ReSample = NULL;
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_SWRESAMPLE
|
||||
if (audio_decoder->Resample) {
|
||||
swr_free(&audio_decoder->Resample);
|
||||
@@ -1147,386 +1112,6 @@ static int CodecAudioPassthroughHelper(AudioDecoder * audio_decoder, const AVPac
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !defined(USE_SWRESAMPLE) && !defined(USE_AVRESAMPLE)
|
||||
|
||||
/**
|
||||
** Set/update audio pts clock.
|
||||
**
|
||||
** @param audio_decoder audio decoder data
|
||||
** @param pts presentation timestamp
|
||||
*/
|
||||
static void CodecAudioSetClock(AudioDecoder * audio_decoder, int64_t pts)
|
||||
{
|
||||
struct timespec nowtime;
|
||||
int64_t delay;
|
||||
int64_t tim_diff;
|
||||
int64_t pts_diff;
|
||||
int drift;
|
||||
int corr;
|
||||
|
||||
AudioSetClock(pts);
|
||||
|
||||
delay = AudioGetDelay();
|
||||
if (!delay) {
|
||||
return;
|
||||
}
|
||||
clock_gettime(CLOCK_MONOTONIC, &nowtime);
|
||||
if (!audio_decoder->LastDelay) {
|
||||
audio_decoder->LastTime = nowtime;
|
||||
audio_decoder->LastPTS = pts;
|
||||
audio_decoder->LastDelay = delay;
|
||||
audio_decoder->Drift = 0;
|
||||
audio_decoder->DriftFrac = 0;
|
||||
Debug(3, "codec/audio: inital drift delay %" PRId64 "ms\n", delay / 90);
|
||||
return;
|
||||
}
|
||||
// collect over some time
|
||||
pts_diff = pts - audio_decoder->LastPTS;
|
||||
if (pts_diff < 10 * 1000 * 90) {
|
||||
return;
|
||||
}
|
||||
|
||||
tim_diff = (nowtime.tv_sec - audio_decoder->LastTime.tv_sec)
|
||||
* 1000 * 1000 * 1000 + (nowtime.tv_nsec - audio_decoder->LastTime.tv_nsec);
|
||||
|
||||
drift = (tim_diff * 90) / (1000 * 1000) - pts_diff + delay - audio_decoder->LastDelay;
|
||||
|
||||
// adjust rounding error
|
||||
nowtime.tv_nsec -= nowtime.tv_nsec % (1000 * 1000 / 90);
|
||||
audio_decoder->LastTime = nowtime;
|
||||
audio_decoder->LastPTS = pts;
|
||||
audio_decoder->LastDelay = delay;
|
||||
|
||||
if (0) {
|
||||
Debug(3, "codec/audio: interval P:%5" PRId64 "ms T:%5" PRId64 "ms D:%4" PRId64 "ms %f %d\n", pts_diff / 90,
|
||||
tim_diff / (1000 * 1000), delay / 90, drift / 90.0, audio_decoder->DriftCorr);
|
||||
}
|
||||
// underruns and av_resample have the same time :(((
|
||||
if (abs(drift) > 10 * 90) {
|
||||
// drift too big, pts changed?
|
||||
Debug(3, "codec/audio: drift(%6d) %3dms reset\n", audio_decoder->DriftCorr, drift / 90);
|
||||
audio_decoder->LastDelay = 0;
|
||||
#ifdef DEBUG
|
||||
corr = 0; // keep gcc happy
|
||||
#endif
|
||||
} else {
|
||||
|
||||
drift += audio_decoder->Drift;
|
||||
audio_decoder->Drift = drift;
|
||||
corr = (10 * audio_decoder->HwSampleRate * drift) / (90 * 1000);
|
||||
// SPDIF/HDMI passthrough
|
||||
if ((CodecAudioDrift & CORRECT_AC3) && (!(CodecPassthrough & CodecAC3)
|
||||
|| audio_decoder->AudioCtx->codec_id != AV_CODEC_ID_AC3)
|
||||
&& (!(CodecPassthrough & CodecEAC3)
|
||||
|| audio_decoder->AudioCtx->codec_id != AV_CODEC_ID_EAC3)) {
|
||||
audio_decoder->DriftCorr = -corr;
|
||||
}
|
||||
|
||||
if (audio_decoder->DriftCorr < -20000) { // limit correction
|
||||
audio_decoder->DriftCorr = -20000;
|
||||
} else if (audio_decoder->DriftCorr > 20000) {
|
||||
audio_decoder->DriftCorr = 20000;
|
||||
}
|
||||
}
|
||||
// FIXME: this works with libav 0.8, and only with >10ms with ffmpeg 0.10
|
||||
if (audio_decoder->AvResample && audio_decoder->DriftCorr) {
|
||||
int distance;
|
||||
|
||||
// try workaround for buggy ffmpeg 0.10
|
||||
if (abs(audio_decoder->DriftCorr) < 2000) {
|
||||
distance = (pts_diff * audio_decoder->HwSampleRate) / (900 * 1000);
|
||||
} else {
|
||||
distance = (pts_diff * audio_decoder->HwSampleRate) / (90 * 1000);
|
||||
}
|
||||
av_resample_compensate(audio_decoder->AvResample, audio_decoder->DriftCorr / 10, distance);
|
||||
}
|
||||
if (1) {
|
||||
static int c;
|
||||
|
||||
if (!(c++ % 10)) {
|
||||
Debug(3, "codec/audio: drift(%6d) %8dus %5d\n", audio_decoder->DriftCorr, drift * 1000 / 90, corr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** Handle audio format changes.
|
||||
**
|
||||
** @param audio_decoder audio decoder data
|
||||
**
|
||||
** @note this is the old not good supported version
|
||||
*/
|
||||
static void CodecAudioUpdateFormat(AudioDecoder * audio_decoder)
|
||||
{
|
||||
int passthrough;
|
||||
const AVCodecContext *audio_ctx;
|
||||
int err;
|
||||
|
||||
if (audio_decoder->ReSample) {
|
||||
audio_resample_close(audio_decoder->ReSample);
|
||||
audio_decoder->ReSample = NULL;
|
||||
}
|
||||
if (audio_decoder->AvResample) {
|
||||
av_resample_close(audio_decoder->AvResample);
|
||||
audio_decoder->AvResample = NULL;
|
||||
audio_decoder->RemainCount = 0;
|
||||
}
|
||||
|
||||
audio_ctx = audio_decoder->AudioCtx;
|
||||
if ((err = CodecAudioUpdateHelper(audio_decoder, &passthrough))) {
|
||||
|
||||
Debug(3, "codec/audio: resample %dHz *%d -> %dHz *%d err %d\n", audio_ctx->sample_rate, audio_ctx->channels,
|
||||
audio_decoder->HwSampleRate, audio_decoder->HwChannels, err);
|
||||
|
||||
if (err == 1) {
|
||||
audio_decoder->ReSample =
|
||||
av_audio_resample_init(audio_decoder->HwChannels, audio_ctx->channels, audio_decoder->HwSampleRate,
|
||||
audio_ctx->sample_rate, audio_ctx->sample_fmt, audio_ctx->sample_fmt, 16, 10, 0, 0.8);
|
||||
// libav-0.8_pre didn't support 6 -> 2 channels
|
||||
if (!audio_decoder->ReSample) {
|
||||
Error(_("codec/audio: resample setup error\n"));
|
||||
audio_decoder->HwChannels = 0;
|
||||
audio_decoder->HwSampleRate = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
Debug(3, "codec/audio: audio setup error\n");
|
||||
// FIXME: handle errors
|
||||
audio_decoder->HwChannels = 0;
|
||||
audio_decoder->HwSampleRate = 0;
|
||||
return;
|
||||
}
|
||||
if (passthrough) { // pass-through no conversion allowed
|
||||
return;
|
||||
}
|
||||
// prepare audio drift resample
|
||||
#ifdef USE_AUDIO_DRIFT_CORRECTION
|
||||
if (CodecAudioDrift & CORRECT_PCM) {
|
||||
if (audio_decoder->AvResample) {
|
||||
Error(_("codec/audio: overwrite resample\n"));
|
||||
}
|
||||
audio_decoder->AvResample =
|
||||
av_resample_init(audio_decoder->HwSampleRate, audio_decoder->HwSampleRate, 16, 10, 0, 0.8);
|
||||
if (!audio_decoder->AvResample) {
|
||||
Error(_("codec/audio: AvResample setup error\n"));
|
||||
} else {
|
||||
// reset drift to some default value
|
||||
audio_decoder->DriftCorr /= 2;
|
||||
audio_decoder->DriftFrac = 0;
|
||||
av_resample_compensate(audio_decoder->AvResample, audio_decoder->DriftCorr / 10,
|
||||
10 * audio_decoder->HwSampleRate);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
** Codec enqueue audio samples.
|
||||
**
|
||||
** @param audio_decoder audio decoder data
|
||||
** @param data samples data
|
||||
** @param count number of bytes in sample data
|
||||
*/
|
||||
void CodecAudioEnqueue(AudioDecoder * audio_decoder, int16_t * data, int count)
|
||||
{
|
||||
#ifdef USE_AUDIO_DRIFT_CORRECTION
|
||||
if ((CodecAudioDrift & CORRECT_PCM) && audio_decoder->AvResample) {
|
||||
int16_t buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 4 + AV_INPUT_BUFFER_PADDING_SIZE]
|
||||
__attribute__((aligned(16)));
|
||||
int16_t buftmp[MAX_CHANNELS][(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 4];
|
||||
int consumed;
|
||||
int i;
|
||||
int n;
|
||||
int ch;
|
||||
int bytes_n;
|
||||
|
||||
bytes_n = count / audio_decoder->HwChannels;
|
||||
// resize sample buffer, if needed
|
||||
if (audio_decoder->RemainCount + bytes_n > audio_decoder->BufferSize) {
|
||||
audio_decoder->BufferSize = audio_decoder->RemainCount + bytes_n;
|
||||
for (ch = 0; ch < MAX_CHANNELS; ++ch) {
|
||||
audio_decoder->Buffer[ch] = realloc(audio_decoder->Buffer[ch], audio_decoder->BufferSize);
|
||||
}
|
||||
}
|
||||
// copy remaining bytes into sample buffer
|
||||
for (ch = 0; ch < audio_decoder->HwChannels; ++ch) {
|
||||
memcpy(audio_decoder->Buffer[ch], audio_decoder->Remain[ch], audio_decoder->RemainCount);
|
||||
}
|
||||
// deinterleave samples into sample buffer
|
||||
for (i = 0; i < bytes_n / 2; i++) {
|
||||
for (ch = 0; ch < audio_decoder->HwChannels; ++ch) {
|
||||
audio_decoder->Buffer[ch][audio_decoder->RemainCount / 2 + i]
|
||||
= data[i * audio_decoder->HwChannels + ch];
|
||||
}
|
||||
}
|
||||
|
||||
bytes_n += audio_decoder->RemainSize;
|
||||
n = 0; // keep gcc lucky
|
||||
// resample the sample buffer into tmp buffer
|
||||
for (ch = 0; ch < audio_decoder->HwChannels; ++ch) {
|
||||
n = av_resample(audio_decoder->AvResample, buftmp[ch], audio_decoder->Buffer[ch], &consumed, bytes_n / 2,
|
||||
sizeof(buftmp[ch]) / 2, ch == audio_decoder->HwChannels - 1);
|
||||
// fixme remaining channels
|
||||
if (bytes_n - consumed * 2 > audio_decoder->RemainSize) {
|
||||
audio_decoder->RemainSize = bytes_n - consumed * 2;
|
||||
}
|
||||
audio_decoder->Remain[ch] = realloc(audio_decoder->Remain[ch], audio_decoder->RemainSize);
|
||||
memcpy(audio_decoder->Remain[ch], audio_decoder->Buffer[ch] + consumed, audio_decoder->RemainSize);
|
||||
audio_decoder->RemainCount = audio_decoder->RemainSize;
|
||||
}
|
||||
|
||||
// interleave samples from sample buffer
|
||||
for (i = 0; i < n; i++) {
|
||||
for (ch = 0; ch < audio_decoder->HwChannels; ++ch) {
|
||||
buf[i * audio_decoder->HwChannels + ch] = buftmp[ch][i];
|
||||
}
|
||||
}
|
||||
n *= 2;
|
||||
|
||||
n *= audio_decoder->HwChannels;
|
||||
if (!(audio_decoder->Passthrough & CodecPCM)) {
|
||||
CodecReorderAudioFrame(buf, n, audio_decoder->HwChannels);
|
||||
}
|
||||
AudioEnqueue(buf, n);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (!(audio_decoder->Passthrough & CodecPCM)) {
|
||||
CodecReorderAudioFrame(data, count, audio_decoder->HwChannels);
|
||||
}
|
||||
AudioEnqueue(data, count);
|
||||
}
|
||||
|
||||
int myavcodec_decode_audio3(AVCodecContext * avctx, int16_t * samples, int *frame_size_ptr, AVPacket * avpkt)
|
||||
{
|
||||
AVFrame *frame = av_frame_alloc();
|
||||
int ret, got_frame = 0;
|
||||
|
||||
if (!frame)
|
||||
return AVERROR(ENOMEM);
|
||||
#if 0
|
||||
ret = avcodec_decode_audio4(avctx, frame, &got_frame, avpkt);
|
||||
#else
|
||||
// SUGGESTION
|
||||
// Now that avcodec_decode_audio4 is deprecated and replaced
|
||||
// by 2 calls (receive frame and send packet), this could be optimized
|
||||
// into separate routines or separate threads.
|
||||
// Also now that it always consumes a whole buffer some code
|
||||
// in the caller may be able to be optimized.
|
||||
ret = avcodec_receive_frame(avctx, frame);
|
||||
if (ret == 0)
|
||||
got_frame = 1;
|
||||
if (ret == AVERROR(EAGAIN))
|
||||
ret = 0;
|
||||
if (ret == 0)
|
||||
ret = avcodec_send_packet(avctx, avpkt);
|
||||
if (ret == AVERROR(EAGAIN))
|
||||
ret = 0;
|
||||
else if (ret < 0) {
|
||||
// Debug(3, "codec/audio: audio decode error: %1 (%2)\n",av_make_error_string(error, sizeof(error), ret),got_frame);
|
||||
return ret;
|
||||
} else
|
||||
ret = avpkt->size;
|
||||
#endif
|
||||
if (ret >= 0 && got_frame) {
|
||||
int i, ch;
|
||||
int planar = av_sample_fmt_is_planar(avctx->sample_fmt);
|
||||
int data_size = av_get_bytes_per_sample(avctx->sample_fmt);
|
||||
|
||||
if (data_size < 0) {
|
||||
/* This should not occur, checking just for paranoia */
|
||||
fprintf(stderr, "Failed to calculate data size\n");
|
||||
exit(1);
|
||||
}
|
||||
for (i = 0; i < frame->nb_samples; i++) {
|
||||
for (ch = 0; ch < avctx->channels; ch++) {
|
||||
memcpy(samples, frame->extended_data[ch] + data_size * i, data_size);
|
||||
samples = (char *)samples + data_size;
|
||||
}
|
||||
}
|
||||
// Debug(3,"data_size %d nb_samples %d sample_fmt %d channels %d planar %d\n",data_size,frame->nb_samples,avctx->sample_fmt,avctx->channels,planar);
|
||||
*frame_size_ptr = data_size * avctx->channels * frame->nb_samples;
|
||||
} else {
|
||||
*frame_size_ptr = 0;
|
||||
}
|
||||
av_frame_free(&frame);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
** Decode an audio packet.
|
||||
**
|
||||
** PTS must be handled self.
|
||||
**
|
||||
** @param audio_decoder audio decoder data
|
||||
** @param avpkt audio packet
|
||||
*/
|
||||
void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
|
||||
{
|
||||
int16_t buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 4 + AV_INPUT_BUFFER_PADDING_SIZE] __attribute__((aligned(16)));
|
||||
int buf_sz;
|
||||
int l;
|
||||
AVCodecContext *audio_ctx;
|
||||
|
||||
audio_ctx = audio_decoder->AudioCtx;
|
||||
|
||||
// FIXME: don't need to decode pass-through codecs
|
||||
buf_sz = sizeof(buf);
|
||||
l = myavcodec_decode_audio3(audio_ctx, buf, &buf_sz, (AVPacket *) avpkt);
|
||||
if (avpkt->size != l) {
|
||||
if (l == AVERROR(EAGAIN)) {
|
||||
Error(_("codec: latm\n"));
|
||||
return;
|
||||
}
|
||||
if (l < 0) { // no audio frame could be decompressed
|
||||
Error(_("codec: error audio data\n"));
|
||||
return;
|
||||
}
|
||||
Error(_("codec: error more than one frame data\n"));
|
||||
}
|
||||
// update audio clock
|
||||
if (avpkt->pts != (int64_t) AV_NOPTS_VALUE) {
|
||||
CodecAudioSetClock(audio_decoder, avpkt->pts);
|
||||
}
|
||||
// FIXME: must first play remainings bytes, than change and play new.
|
||||
if (audio_decoder->Passthrough != CodecPassthrough || audio_decoder->SampleRate != audio_ctx->sample_rate
|
||||
|| audio_decoder->Channels != audio_ctx->channels) {
|
||||
CodecAudioUpdateFormat(audio_decoder);
|
||||
}
|
||||
|
||||
if (audio_decoder->HwSampleRate && audio_decoder->HwChannels) {
|
||||
// need to resample audio
|
||||
if (audio_decoder->ReSample) {
|
||||
int16_t outbuf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 4 + AV_INPUT_BUFFER_PADDING_SIZE]
|
||||
__attribute__((aligned(16)));
|
||||
int outlen;
|
||||
|
||||
// FIXME: libav-0.7.2 crash here
|
||||
outlen = audio_resample(audio_decoder->ReSample, outbuf, buf, buf_sz);
|
||||
#ifdef DEBUG
|
||||
if (outlen != buf_sz) {
|
||||
Debug(3, "codec/audio: possible fixed ffmpeg\n");
|
||||
}
|
||||
#endif
|
||||
if (outlen) {
|
||||
// outlen seems to be wrong in ffmpeg-0.9
|
||||
outlen /= audio_decoder->Channels * av_get_bytes_per_sample(audio_ctx->sample_fmt);
|
||||
outlen *= audio_decoder->HwChannels * av_get_bytes_per_sample(audio_ctx->sample_fmt);
|
||||
Debug(4, "codec/audio: %d -> %d\n", buf_sz, outlen);
|
||||
CodecAudioEnqueue(audio_decoder, outbuf, outlen);
|
||||
}
|
||||
} else {
|
||||
if (CodecAudioPassthroughHelper(audio_decoder, avpkt)) {
|
||||
return;
|
||||
}
|
||||
|
||||
CodecAudioEnqueue(audio_decoder, buf, buf_sz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(USE_SWRESAMPLE) || defined(USE_AVRESAMPLE)
|
||||
|
||||
/**
|
||||
@@ -1787,6 +1372,7 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
|
||||
*/
|
||||
void CodecAudioFlushBuffers(AudioDecoder * decoder)
|
||||
{
|
||||
|
||||
avcodec_flush_buffers(decoder->AudioCtx);
|
||||
}
|
||||
|
||||
|
129
drm.c
129
drm.c
@@ -18,13 +18,13 @@ struct _Drm_Render_
|
||||
int fd_drm;
|
||||
drmModeModeInfo mode;
|
||||
drmModeCrtc *saved_crtc;
|
||||
// drmEventContext ev;
|
||||
// drmEventContext ev;
|
||||
int bpp;
|
||||
uint32_t connector_id, crtc_id, video_plane;
|
||||
uint32_t hdr_metadata;
|
||||
uint32_t mmWidth,mmHeight; // Size in mm
|
||||
uint32_t hdr_blob_id;
|
||||
|
||||
|
||||
};
|
||||
typedef struct _Drm_Render_ VideoRender;
|
||||
|
||||
@@ -193,12 +193,12 @@ void set_video_mode(int width, int height)
|
||||
return;
|
||||
connector = drmModeGetConnector(render->fd_drm, render->connector_id);
|
||||
for (ii = 0; ii < connector->count_modes; ii++) {
|
||||
mode = &connector->modes[ii];
|
||||
mode = &connector->modes[ii];
|
||||
printf("Mode %d %dx%d Rate %d\n",ii,mode->hdisplay,mode->vdisplay,mode->vrefresh);
|
||||
if (width == mode->hdisplay &&
|
||||
height == mode->vdisplay &&
|
||||
if (width == mode->hdisplay &&
|
||||
height == mode->vdisplay &&
|
||||
mode->vrefresh == DRMRefresh &&
|
||||
render->mode.hdisplay != width &&
|
||||
render->mode.hdisplay != width &&
|
||||
render->mode.vdisplay != height &&
|
||||
!(mode->flags & DRM_MODE_FLAG_INTERLACE)) {
|
||||
memcpy(&render->mode, mode, sizeof(drmModeModeInfo));
|
||||
@@ -211,7 +211,7 @@ void set_video_mode(int width, int height)
|
||||
CuvidSetVideoMode();
|
||||
Debug(3,"Set new mode %d:%d\n",mode->hdisplay,mode->vdisplay);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,11 +240,31 @@ static int FindDevice(VideoRender * render)
|
||||
fprintf(stderr, "FindDevice: cannot open /dev/dri/card0: %m\n");
|
||||
return -errno;
|
||||
}
|
||||
drmSetMaster(render->fd_drm);
|
||||
|
||||
int ret = drmSetMaster(render->fd_drm);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
drm_magic_t magic;
|
||||
|
||||
ret = drmGetMagic(render->fd_drm, &magic);
|
||||
if (ret < 0)
|
||||
{
|
||||
Debug(3, "drm:%s - failed to get drm magic: %s\n", __FUNCTION__, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = drmAuthMagic(render->fd_drm, magic);
|
||||
if (ret < 0)
|
||||
{
|
||||
Debug(3, "drm:%s - failed to authorize drm magic: %s\n", __FUNCTION__, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
version = drmGetVersion(render->fd_drm);
|
||||
fprintf(stderr, "FindDevice: open /dev/dri/card0: %s\n", version->name);
|
||||
|
||||
|
||||
// check capability
|
||||
if (drmGetCap(render->fd_drm, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0 || has_dumb == 0)
|
||||
fprintf(stderr, "FindDevice: drmGetCap DRM_CAP_DUMB_BUFFER failed or doesn't have dumb buffer\n");
|
||||
@@ -263,7 +283,7 @@ static int FindDevice(VideoRender * render)
|
||||
|
||||
if (drmGetCap(render->fd_drm, DRM_PRIME_CAP_IMPORT, &has_prime) < 0)
|
||||
fprintf(stderr, "FindDevice: DRM_PRIME_CAP_IMPORT not available.\n");
|
||||
|
||||
|
||||
if ((resources = drmModeGetResources(render->fd_drm)) == NULL){
|
||||
fprintf(stderr, "FindDevice: cannot retrieve DRM resources (%d): %m\n", errno);
|
||||
return -errno;
|
||||
@@ -282,18 +302,18 @@ static int FindDevice(VideoRender * render)
|
||||
fprintf(stderr, "FindDevice: cannot retrieve DRM connector (%d): %m\n", errno);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
|
||||
sprintf(connectorstr,"%s-%u",util_lookup_connector_type_name(connector->connector_type),connector->connector_type_id);
|
||||
printf("Connector >%s< is %sconnected\n",connectorstr,connector->connection == DRM_MODE_CONNECTED?"":"not ");
|
||||
if (DRMConnector && strcmp(DRMConnector,connectorstr))
|
||||
continue;
|
||||
|
||||
|
||||
if (connector->connection == DRM_MODE_CONNECTED && connector->count_modes > 0) {
|
||||
float aspect = (float)connector->mmWidth / (float)connector->mmHeight;
|
||||
if ((aspect > 1.70) && (aspect < 1.85)) {
|
||||
render->mmHeight = 90;
|
||||
render->mmWidth = 160;
|
||||
} else {
|
||||
} else {
|
||||
render->mmHeight = connector->mmHeight;
|
||||
render->mmWidth = connector->mmWidth;
|
||||
}
|
||||
@@ -304,27 +324,27 @@ static int FindDevice(VideoRender * render)
|
||||
return -errno;
|
||||
}
|
||||
render->crtc_id = encoder->crtc_id;
|
||||
|
||||
|
||||
render->hdr_metadata = GetPropertyID(render->fd_drm, connector->connector_id,
|
||||
DRM_MODE_OBJECT_CONNECTOR, "HDR_OUTPUT_METADATA");
|
||||
DRM_MODE_OBJECT_CONNECTOR, "HDR_OUTPUT_METADATA");
|
||||
printf("ID %d of METADATA in Connector %d connected %d\n",render->hdr_metadata,connector->connector_id,connector->connection);
|
||||
|
||||
|
||||
memcpy(&render->mode, &connector->modes[0], sizeof(drmModeModeInfo)); // set fallback
|
||||
// search Modes for Connector
|
||||
for (ii = 0; ii < connector->count_modes; ii++) {
|
||||
mode = &connector->modes[ii];
|
||||
|
||||
|
||||
printf("Mode %d %dx%d Rate %d\n",ii,mode->hdisplay,mode->vdisplay,mode->vrefresh);
|
||||
|
||||
if (VideoWindowWidth && VideoWindowHeight) { // preset by command line
|
||||
if (VideoWindowWidth == mode->hdisplay &&
|
||||
VideoWindowHeight == mode->vdisplay &&
|
||||
|
||||
if (VideoWindowWidth && VideoWindowHeight) { // preset by command line
|
||||
if (VideoWindowWidth == mode->hdisplay &&
|
||||
VideoWindowHeight == mode->vdisplay &&
|
||||
mode->vrefresh == DRMRefresh &&
|
||||
!(mode->flags & DRM_MODE_FLAG_INTERLACE)) {
|
||||
memcpy(&render->mode, mode, sizeof(drmModeModeInfo));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!(mode->flags & DRM_MODE_FLAG_INTERLACE)) {
|
||||
memcpy(&render->mode, mode, sizeof(drmModeModeInfo));
|
||||
@@ -335,7 +355,7 @@ static int FindDevice(VideoRender * render)
|
||||
}
|
||||
}
|
||||
found = 1;
|
||||
i = resources->count_connectors; // uuuuhh
|
||||
i = resources->count_connectors; // uuuuhh
|
||||
}
|
||||
VideoWindowWidth = render->mode.hdisplay;
|
||||
VideoWindowHeight = render->mode.vdisplay;
|
||||
@@ -348,7 +368,7 @@ static int FindDevice(VideoRender * render)
|
||||
printf("Requested Connector not found or not connected\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// find first plane
|
||||
if ((plane_res = drmModeGetPlaneResources(render->fd_drm)) == NULL)
|
||||
fprintf(stderr, "FindDevice: cannot retrieve PlaneResources (%d): %m\n", errno);
|
||||
@@ -366,7 +386,7 @@ static int FindDevice(VideoRender * render)
|
||||
|
||||
uint64_t type = GetPropertyValue(render->fd_drm, plane_res->planes[j],
|
||||
DRM_MODE_OBJECT_PLANE, "type");
|
||||
uint64_t zpos = 0;
|
||||
uint64_t zpos = 0;
|
||||
|
||||
#ifdef DRM_DEBUG // If more then 2 crtcs this must rewriten!!!
|
||||
printf("[FindDevice] Plane id %i crtc_id %i possible_crtcs %i possible CRTC %i type %s\n",
|
||||
@@ -384,7 +404,7 @@ static int FindDevice(VideoRender * render)
|
||||
case DRM_FORMAT_ARGB8888:
|
||||
#else
|
||||
case DRM_FORMAT_XRGB2101010:
|
||||
#endif
|
||||
#endif
|
||||
if (!render->video_plane) {
|
||||
render->video_plane = plane->plane_id;
|
||||
}
|
||||
@@ -419,25 +439,25 @@ static int FindDevice(VideoRender * render)
|
||||
void VideoInitDrm()
|
||||
{
|
||||
int i;
|
||||
|
||||
|
||||
|
||||
|
||||
if (!(render = calloc(1, sizeof(*render)))) {
|
||||
Fatal(_("video/DRM: out of memory\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (FindDevice(render)){
|
||||
Fatal(_( "VideoInit: FindDevice() failed\n"));
|
||||
}
|
||||
|
||||
|
||||
gbm.dev = gbm_create_device (render->fd_drm);
|
||||
assert (gbm.dev != NULL);
|
||||
|
||||
|
||||
PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display = NULL;
|
||||
get_platform_display =
|
||||
(void *) eglGetProcAddress("eglGetPlatformDisplay");
|
||||
assert(get_platform_display != NULL);
|
||||
|
||||
|
||||
eglDisplay = get_platform_display(EGL_PLATFORM_GBM_KHR, gbm.dev, NULL);
|
||||
|
||||
assert (eglDisplay != NULL);
|
||||
@@ -462,22 +482,21 @@ void VideoInitDrm()
|
||||
DRM_MODE_OBJECT_CONNECTOR, "CRTC_ID", render->crtc_id);
|
||||
SetPropertyRequest(ModeReq, render->fd_drm, render->crtc_id,
|
||||
DRM_MODE_OBJECT_CRTC, "ACTIVE", 1);
|
||||
|
||||
|
||||
if (drmModeAtomicCommit(render->fd_drm, ModeReq, flags, NULL) != 0)
|
||||
fprintf(stderr, "cannot set atomic mode (%d): %m\n", errno);
|
||||
|
||||
|
||||
if (drmModeDestroyPropertyBlob(render->fd_drm, modeID) != 0)
|
||||
fprintf(stderr, "cannot destroy property blob (%d): %m\n", errno);
|
||||
|
||||
|
||||
drmModeAtomicFree(ModeReq);
|
||||
|
||||
}
|
||||
|
||||
void get_drm_aspect(int *num,int *den)
|
||||
{
|
||||
Debug(3,"mmHeight %d mmWidth %d VideoHeight %d VideoWidth %d\n",render->mmHeight,render->mmWidth,VideoWindowHeight,VideoWindowWidth);
|
||||
*num = VideoWindowWidth * render->mmHeight;
|
||||
*den = VideoWindowHeight * render->mmWidth;
|
||||
*num = VideoWindowWidth;
|
||||
*den = VideoWindowHeight;
|
||||
}
|
||||
|
||||
struct gbm_bo *bo = NULL, *next_bo=NULL;
|
||||
@@ -488,8 +507,8 @@ static int old_color=-1,old_trc=-1;
|
||||
void InitBo(int bpp) {
|
||||
// create the GBM and EGL surface
|
||||
render->bpp = bpp;
|
||||
gbm.surface = gbm_surface_create (gbm.dev, VideoWindowWidth,VideoWindowHeight,
|
||||
bpp==10?GBM_FORMAT_XRGB2101010:GBM_FORMAT_ARGB8888,
|
||||
gbm.surface = gbm_surface_create (gbm.dev, VideoWindowWidth,VideoWindowHeight,
|
||||
bpp==10?GBM_FORMAT_XRGB2101010:GBM_FORMAT_ARGB8888,
|
||||
GBM_BO_USE_SCANOUT|GBM_BO_USE_RENDERING);
|
||||
assert(gbm.surface != NULL);
|
||||
eglSurface = eglCreateWindowSurface (eglDisplay, eglConfig, gbm.surface, NULL);
|
||||
@@ -501,10 +520,10 @@ static struct gbm_bo *previous_bo = NULL;
|
||||
static uint32_t previous_fb;
|
||||
|
||||
static void drm_swap_buffers () {
|
||||
|
||||
|
||||
uint32_t fb;
|
||||
|
||||
eglSwapBuffers (eglDisplay, eglSurface);
|
||||
|
||||
eglSwapBuffers (eglDisplay, eglSurface);
|
||||
struct gbm_bo *bo = gbm_surface_lock_front_buffer (gbm.surface);
|
||||
#if 1
|
||||
if (bo == NULL)
|
||||
@@ -517,7 +536,7 @@ static void drm_swap_buffers () {
|
||||
|
||||
drmModeAddFB (render->fd_drm, VideoWindowWidth,VideoWindowHeight,render->bpp==10? 30:24, 32, pitch, handle, &fb);
|
||||
// drmModeSetCrtc (render->fd_drm, render->crtc_id, fb, 0, 0, &render->connector_id, 1, &render->mode);
|
||||
|
||||
|
||||
if (m_need_modeset) {
|
||||
drmModeAtomicReqPtr ModeReq;
|
||||
const uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
|
||||
@@ -531,14 +550,14 @@ static void drm_swap_buffers () {
|
||||
fprintf(stderr, "cannot allocate atomic request (%d): %m\n", errno);
|
||||
return;
|
||||
}
|
||||
|
||||
// Need to disable the CRTC in order to submit the HDR data....
|
||||
|
||||
// Need to disable the CRTC in order to submit the HDR data....
|
||||
SetPropertyRequest(ModeReq, render->fd_drm, render->crtc_id,
|
||||
DRM_MODE_OBJECT_CRTC, "ACTIVE", 0);
|
||||
DRM_MODE_OBJECT_CRTC, "ACTIVE", 0);
|
||||
if (drmModeAtomicCommit(render->fd_drm, ModeReq, flags, NULL) != 0)
|
||||
fprintf(stderr, "cannot set atomic mode (%d): %m\n", errno);
|
||||
sleep(2);
|
||||
|
||||
|
||||
SetPropertyRequest(ModeReq, render->fd_drm, render->connector_id,
|
||||
DRM_MODE_OBJECT_CONNECTOR, "Colorspace",old_color==AVCOL_PRI_BT2020?9:2 );
|
||||
SetPropertyRequest(ModeReq, render->fd_drm, render->crtc_id,
|
||||
@@ -547,7 +566,7 @@ static void drm_swap_buffers () {
|
||||
DRM_MODE_OBJECT_CONNECTOR, "CRTC_ID", render->crtc_id);
|
||||
SetPropertyRequest(ModeReq, render->fd_drm, render->crtc_id,
|
||||
DRM_MODE_OBJECT_CRTC, "ACTIVE", 1);
|
||||
|
||||
|
||||
if (drmModeAtomicCommit(render->fd_drm, ModeReq, flags, NULL) != 0)
|
||||
fprintf(stderr, "cannot set atomic mode (%d): %m\n", errno);
|
||||
|
||||
@@ -558,7 +577,7 @@ static void drm_swap_buffers () {
|
||||
m_need_modeset = 0;
|
||||
}
|
||||
drmModeSetCrtc (render->fd_drm, render->crtc_id, fb, 0, 0, &render->connector_id, 1, &render->mode);
|
||||
|
||||
|
||||
if (previous_bo) {
|
||||
drmModeRmFB (render->fd_drm, previous_fb);
|
||||
gbm_surface_release_buffer (gbm.surface, previous_bo);
|
||||
@@ -579,15 +598,15 @@ static void drm_clean_up () {
|
||||
drmModeRmFB (render->fd_drm, previous_fb);
|
||||
gbm_surface_release_buffer (gbm.surface, previous_bo);
|
||||
}
|
||||
|
||||
|
||||
drmModeSetCrtc (render->fd_drm, render->saved_crtc->crtc_id, render->saved_crtc->buffer_id,
|
||||
render->saved_crtc->x, render->saved_crtc->y, &render->connector_id, 1, &render->saved_crtc->mode);
|
||||
drmModeFreeCrtc (render->saved_crtc);
|
||||
|
||||
|
||||
if (render->hdr_blob_id)
|
||||
drmModeDestroyPropertyBlob(render->fd_drm, render->hdr_blob_id);
|
||||
render->hdr_blob_id = 0;
|
||||
|
||||
|
||||
eglDestroySurface (eglDisplay, eglSurface);
|
||||
EglCheck();
|
||||
gbm_surface_destroy (gbm.surface);
|
||||
@@ -597,9 +616,9 @@ static void drm_clean_up () {
|
||||
EglCheck();
|
||||
eglSharedContext = NULL;
|
||||
|
||||
eglTerminate (eglDisplay);
|
||||
eglTerminate (eglDisplay);
|
||||
EglCheck();
|
||||
|
||||
|
||||
gbm_device_destroy (gbm.dev);
|
||||
drmDropMaster(render->fd_drm);
|
||||
close (render->fd_drm);
|
||||
|
@@ -17,8 +17,6 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cuda_cuda_h__ // check to see if CUDA_H is included above
|
||||
|
||||
// Error Code string definitions here
|
||||
typedef struct
|
||||
{
|
||||
@@ -453,6 +451,4 @@ static inline const char *getCudaDrvErrorString(CUresult error_id)
|
||||
return (const char *)"CUDA_ERROR not found!";
|
||||
}
|
||||
|
||||
#endif // __cuda_cuda_h__
|
||||
|
||||
#endif
|
||||
|
42
hdr.c
42
hdr.c
@@ -334,11 +334,11 @@ static void set_hdr_metadata(int color,int trc, AVFrameSideData *sd1, AVFrameSid
|
||||
int max_lum=4000,min_lum=0050;
|
||||
struct AVMasteringDisplayMetadata *md = NULL;
|
||||
struct AVContentLightMetadata *ld = NULL;
|
||||
|
||||
|
||||
if (render->hdr_metadata == -1) { // Metadata not supported
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// clean up FFMEPG stuff
|
||||
if (trc == AVCOL_TRC_BT2020_10)
|
||||
trc = AVCOL_TRC_ARIB_STD_B67;
|
||||
@@ -346,16 +346,16 @@ static void set_hdr_metadata(int color,int trc, AVFrameSideData *sd1, AVFrameSid
|
||||
trc = AVCOL_TRC_BT709;
|
||||
if (color == AVCOL_PRI_UNSPECIFIED)
|
||||
color = AVCOL_PRI_BT709;
|
||||
|
||||
|
||||
if ((old_color == color && old_trc == trc && !sd1 && !sd2) || !render->hdr_metadata)
|
||||
return; // nothing to do
|
||||
|
||||
|
||||
if (sd1)
|
||||
md = sd1->data;
|
||||
|
||||
|
||||
if (sd2)
|
||||
ld = sd2->data;
|
||||
|
||||
|
||||
if (md && !memcmp(md,&md_save,sizeof(md_save)))
|
||||
if (ld && !memcmp(ld,&ld_save,sizeof(ld_save))) {
|
||||
return;
|
||||
@@ -363,23 +363,23 @@ static void set_hdr_metadata(int color,int trc, AVFrameSideData *sd1, AVFrameSid
|
||||
else if (ld && !memcmp(ld,&ld_save,sizeof(ld_save))) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (ld)
|
||||
memcpy(&ld_save,ld,sizeof(ld_save));
|
||||
if (md)
|
||||
memcpy(&md_save,md,sizeof(md_save));
|
||||
|
||||
|
||||
Debug(3,"Update HDR to TRC %d color %d\n",trc,color);
|
||||
|
||||
if (trc == AVCOL_TRC_BT2020_10)
|
||||
trc = AVCOL_TRC_ARIB_STD_B67;
|
||||
|
||||
|
||||
old_color = color;
|
||||
old_trc = trc;
|
||||
|
||||
|
||||
if (render->hdr_blob_id)
|
||||
drmModeDestroyPropertyBlob(render->fd_drm, render->hdr_blob_id);
|
||||
|
||||
|
||||
switch(trc) {
|
||||
case AVCOL_TRC_BT709: // 1
|
||||
case AVCOL_TRC_UNSPECIFIED: // 2
|
||||
@@ -387,16 +387,17 @@ static void set_hdr_metadata(int color,int trc, AVFrameSideData *sd1, AVFrameSid
|
||||
break;
|
||||
case AVCOL_TRC_BT2020_10: // 14
|
||||
case AVCOL_TRC_BT2020_12:
|
||||
case AVCOL_TRC_ARIB_STD_B67: // 18 HLG
|
||||
case AVCOL_TRC_ARIB_STD_B67: // 18 HLG
|
||||
eotf = EOTF_HLG;
|
||||
break;
|
||||
case AVCOL_TRC_SMPTE2084: // 16
|
||||
eotf = EOTF_ST2084;
|
||||
break;
|
||||
default:
|
||||
eotf = EOTF_TRADITIONAL_GAMMA_SDR;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
switch (color) {
|
||||
case AVCOL_PRI_BT709: // 1
|
||||
case AVCOL_PRI_UNSPECIFIED: // 2
|
||||
@@ -412,7 +413,7 @@ static void set_hdr_metadata(int color,int trc, AVFrameSideData *sd1, AVFrameSid
|
||||
cs = weston_colorspace_lookup("BT.709");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (md) { // we got Metadata
|
||||
if (md->has_primaries) {
|
||||
Debug(3,"Mastering Display Metadata,\n has_primaries:%d has_luminance:%d \n"
|
||||
@@ -464,9 +465,9 @@ static void set_hdr_metadata(int color,int trc, AVFrameSideData *sd1, AVFrameSid
|
||||
MaxCLL, // Maximum Content Light Level (MaxCLL)
|
||||
MaxFALL, // Maximum Frame-Average Light Level (MaxFALL)
|
||||
eotf);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
ret = drmModeCreatePropertyBlob(render->fd_drm, &data, sizeof(data), &render->hdr_blob_id);
|
||||
if (ret) {
|
||||
printf("DRM: HDR metadata: failed blob create \n");
|
||||
@@ -478,15 +479,14 @@ static void set_hdr_metadata(int color,int trc, AVFrameSideData *sd1, AVFrameSid
|
||||
render->hdr_metadata, render->hdr_blob_id);
|
||||
if (ret) {
|
||||
printf("DRM: HDR metadata: failed property set %d\n",ret);
|
||||
|
||||
|
||||
if (render->hdr_blob_id)
|
||||
drmModeDestroyPropertyBlob(render->fd_drm, render->hdr_blob_id);
|
||||
render->hdr_blob_id = 0;
|
||||
return;
|
||||
}
|
||||
m_need_modeset = 1;
|
||||
|
||||
Debug(3,"DRM: HDR metadata: prop set\n");
|
||||
|
||||
}
|
||||
|
||||
Debug(3,"DRM: HDR metadata: prop set\n");
|
||||
|
||||
}
|
||||
|
1031
openglosd.cpp
1031
openglosd.cpp
File diff suppressed because it is too large
Load Diff
18
openglosd.h
18
openglosd.h
@@ -103,14 +103,14 @@ class cOglGlyph:public cListObject
|
||||
struct tKerning
|
||||
{
|
||||
public:
|
||||
tKerning(uint prevSym, GLfloat kerning = 0.0f) {
|
||||
tKerning(FT_ULong prevSym, GLfloat kerning = 0.0f) {
|
||||
this->prevSym = prevSym;
|
||||
this->kerning = kerning;
|
||||
}
|
||||
uint prevSym;
|
||||
FT_ULong prevSym;
|
||||
GLfloat kerning;
|
||||
};
|
||||
uint charCode;
|
||||
FT_ULong charCode;
|
||||
int bearingLeft;
|
||||
int bearingTop;
|
||||
int width;
|
||||
@@ -122,9 +122,9 @@ class cOglGlyph:public cListObject
|
||||
void LoadTexture(FT_BitmapGlyph ftGlyph);
|
||||
|
||||
public:
|
||||
cOglGlyph(uint charCode, FT_BitmapGlyph ftGlyph);
|
||||
cOglGlyph(FT_ULong charCode, FT_BitmapGlyph ftGlyph);
|
||||
virtual ~ cOglGlyph();
|
||||
uint CharCode(void)
|
||||
FT_ULong CharCode(void)
|
||||
{
|
||||
return charCode;
|
||||
}
|
||||
@@ -148,8 +148,8 @@ class cOglGlyph:public cListObject
|
||||
{
|
||||
return height;
|
||||
}
|
||||
int GetKerningCache(uint prevSym);
|
||||
void SetKerningCache(uint prevSym, int kerning);
|
||||
int GetKerningCache(FT_ULong prevSym);
|
||||
void SetKerningCache(FT_ULong prevSym, int kerning);
|
||||
void BindTexture(void);
|
||||
};
|
||||
|
||||
@@ -190,8 +190,8 @@ class cOglFont:public cListObject
|
||||
{
|
||||
return height;
|
||||
};
|
||||
cOglGlyph *Glyph(uint charCode) const;
|
||||
int Kerning(cOglGlyph * glyph, uint prevSym) const;
|
||||
cOglGlyph *Glyph(FT_ULong charCode) const;
|
||||
int Kerning(cOglGlyph * glyph, FT_ULong prevSym) const;
|
||||
};
|
||||
|
||||
/****************************************************************************************
|
||||
|
58
po/de_DE.po
58
po/de_DE.po
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: VDR \n"
|
||||
"Report-Msgid-Bugs-To: <see README>\n"
|
||||
"POT-Creation-Date: 2019-10-26 18:41+0200\n"
|
||||
"POT-Creation-Date: 2020-04-15 18:57+0200\n"
|
||||
"PO-Revision-Date: blabla\n"
|
||||
"Last-Translator: blabla\n"
|
||||
"Language-Team: blabla\n"
|
||||
@@ -263,9 +263,6 @@ msgstr ""
|
||||
msgid "codec: can't allocate video codec context\n"
|
||||
msgstr ""
|
||||
|
||||
msgid "VAAPI Refcounts invalid\n"
|
||||
msgstr ""
|
||||
|
||||
msgid "codec: can't set option deint to video codec!\n"
|
||||
msgstr ""
|
||||
|
||||
@@ -306,24 +303,6 @@ msgstr ""
|
||||
msgid "codec/audio: decoded data smaller than encoded\n"
|
||||
msgstr ""
|
||||
|
||||
msgid "codec/audio: resample setup error\n"
|
||||
msgstr ""
|
||||
|
||||
msgid "codec/audio: overwrite resample\n"
|
||||
msgstr ""
|
||||
|
||||
msgid "codec/audio: AvResample setup error\n"
|
||||
msgstr ""
|
||||
|
||||
msgid "codec: latm\n"
|
||||
msgstr ""
|
||||
|
||||
msgid "codec: error audio data\n"
|
||||
msgstr ""
|
||||
|
||||
msgid "codec: error more than one frame data\n"
|
||||
msgstr ""
|
||||
|
||||
msgid "codec/audio: can't setup resample\n"
|
||||
msgstr ""
|
||||
|
||||
@@ -471,18 +450,6 @@ msgstr "Schneide oben und unten ab (Pixel)"
|
||||
msgid "Cut left and right (pixel)"
|
||||
msgstr "Schneide links und rechts ab (Pixel)"
|
||||
|
||||
msgid "Auto-crop"
|
||||
msgstr ""
|
||||
|
||||
msgid "Autocrop interval (frames)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Autocrop delay (n * interval)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Autocrop tolerance (pixel)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Audio"
|
||||
msgstr "Audio"
|
||||
|
||||
@@ -642,7 +609,7 @@ msgid " Frames missed(%d) duped(%d) dropped(%d) total(%d)"
|
||||
msgstr " Frames verloren(%d) verdoppelt(%d) übersprungen(%d) Gesamt(%d)"
|
||||
|
||||
#, c-format
|
||||
msgid " Frame Process time %2.2fms"
|
||||
msgid " Video %dx%d Color: %s Gamma: %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "pass-through disabled"
|
||||
@@ -661,12 +628,6 @@ msgstr ""
|
||||
msgid "surround downmix disabled"
|
||||
msgstr ""
|
||||
|
||||
msgid "auto-crop disabled and freezed"
|
||||
msgstr ""
|
||||
|
||||
msgid "auto-crop enabled"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "[softhddev]: hot key %d is not supported\n"
|
||||
msgstr ""
|
||||
@@ -807,10 +768,6 @@ msgstr ""
|
||||
msgid "video/glx: no GLX support\n"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "video/glx: glx version %d.%d\n"
|
||||
msgstr ""
|
||||
|
||||
msgid "did not get FBconfig"
|
||||
msgstr ""
|
||||
|
||||
@@ -898,11 +855,10 @@ msgid "Failed rendering frame!\n"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "video/vdpau: output buffer full, dropping frame (%d/%d)\n"
|
||||
msgid "video/cuvid: output buffer full, dropping frame (%d/%d)\n"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "video/vdpau: pixel format %d not supported\n"
|
||||
msgid "Could not dynamically load CUDA\n"
|
||||
msgstr ""
|
||||
|
||||
msgid "Kein Cuda device gefunden"
|
||||
@@ -943,12 +899,6 @@ msgstr ""
|
||||
msgid "video/egl: can't create thread egl context\n"
|
||||
msgstr ""
|
||||
|
||||
msgid "video: can't queue cancel video display thread\n"
|
||||
msgstr ""
|
||||
|
||||
msgid "video: can't cancel video display thread\n"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "video: repeated pict %d found, but not handled\n"
|
||||
msgstr ""
|
||||
|
409
shaders.h
409
shaders.h
@@ -1,4 +1,5 @@
|
||||
// shader
|
||||
#define SHADER_LENGTH 10000
|
||||
|
||||
#ifdef CUVID
|
||||
const char *gl_version = "#version 330";
|
||||
@@ -10,174 +11,6 @@ const char *gl_version = "#version 300 es ";
|
||||
#endif
|
||||
#endif
|
||||
|
||||
char vertex_3[] = {"\
|
||||
%s\n\
|
||||
in vec2 vertex_position;\n\
|
||||
in vec2 vertex_texcoord0;\n\
|
||||
out vec2 texcoord0;\n\
|
||||
in vec2 vertex_texcoord1;\n\
|
||||
out vec2 texcoord1;\n\
|
||||
in vec2 vertex_texcoord2;\n\
|
||||
out vec2 texcoord2;\n\
|
||||
void main() {\n\
|
||||
gl_Position = vec4(vertex_position, 1.0, 1.0);\n\
|
||||
texcoord0 = vertex_texcoord0;\n\
|
||||
texcoord1 = vertex_texcoord1;\n\
|
||||
texcoord2 = vertex_texcoord1;\n\
|
||||
}\n"};
|
||||
|
||||
char fragment_3[] = {"\
|
||||
%s\n\
|
||||
#define texture1D texture\n\
|
||||
#define texture3D texture\n\
|
||||
precision mediump float; \
|
||||
layout(location = 0) out vec4 out_color;\n\
|
||||
in vec2 texcoord0;\n\
|
||||
in vec2 texcoord1;\n\
|
||||
in vec2 texcoord2;\n\
|
||||
uniform mat3 colormatrix;\n\
|
||||
uniform vec3 colormatrix_c;\n\
|
||||
uniform sampler2D texture0;\n\
|
||||
uniform sampler2D texture1;\n\
|
||||
uniform sampler2D texture2;\n\
|
||||
//#define LUT_POS(x, lut_size) mix(0.5 / (lut_size), 1.0 - 0.5 / (lut_size), (x))\n\
|
||||
void main() {\n\
|
||||
vec4 color; // = vec4(0.0, 0.0, 0.0, 1.0);\n\
|
||||
color.r = 1.000000 * vec4(texture(texture0, texcoord0)).r;\n\
|
||||
color.g = 1.000000 * vec4(texture(texture1, texcoord1)).r;\n\
|
||||
color.b = 1.000000 * vec4(texture(texture2, texcoord2)).r;\n\
|
||||
// color conversion\n\
|
||||
color.rgb = mat3(colormatrix) * color.rgb + colormatrix_c;\n\
|
||||
color.a = 1.0;\n\
|
||||
// color mapping\n\
|
||||
out_color = color;\n\
|
||||
}\n"};
|
||||
|
||||
char fragment_bt2100_3[] = {"\
|
||||
%s\n \
|
||||
#define texture1D texture\n\
|
||||
#define texture3D texture\n\
|
||||
precision mediump float; \
|
||||
layout(location = 0) out vec4 out_color;\n\
|
||||
in vec2 texcoord0;\n\
|
||||
in vec2 texcoord1;\n\
|
||||
in vec2 texcoord2;\n\
|
||||
uniform mat3 colormatrix;\n\
|
||||
uniform vec3 colormatrix_c;\n\
|
||||
uniform mat3 cms_matrix;\n\
|
||||
uniform sampler2D texture0;\n\
|
||||
uniform sampler2D texture1;\n\
|
||||
uniform sampler2D texture2;\n\
|
||||
//#define LUT_POS(x, lut_size) mix(0.5 / (lut_size), 1.0 - 0.5 / (lut_size), (x))\n\
|
||||
void main() {\n\
|
||||
vec4 color; // = vec4(0.0, 0.0, 0.0, 1.0);\n\
|
||||
color.r = 1.003906 * vec4(texture(texture0, texcoord0)).r;\n\
|
||||
color.g = 1.003906 * vec4(texture(texture1, texcoord1)).r;\n\
|
||||
color.b = 1.003906 * vec4(texture(texture2, texcoord2)).r;\n\
|
||||
// color conversion\n\
|
||||
color.rgb = mat3(colormatrix) * color.rgb + colormatrix_c;\n\
|
||||
color.a = 1.0;\n\
|
||||
// color mapping\n\
|
||||
color.rgb = clamp(color.rgb, 0.0, 1.0);\n\
|
||||
color.rgb = pow(color.rgb, vec3(2.4));\n\
|
||||
color.rgb = cms_matrix * color.rgb;\n\
|
||||
color.rgb = clamp(color.rgb, 0.0, 1.0);\n\
|
||||
color.rgb = pow(color.rgb, vec3(1.0/2.4));\n\
|
||||
out_color = color;\n\
|
||||
}\n"};
|
||||
|
||||
|
||||
char vertex_osd[] = { "\
|
||||
%s\n\
|
||||
in vec2 vertex_position;\n\
|
||||
in vec2 vertex_texcoord0;\n\
|
||||
out vec2 texcoord0;\n\
|
||||
void main() {\n\
|
||||
gl_Position = vec4(vertex_position, 1.0, 1.0);\n\
|
||||
texcoord0 = vertex_texcoord0;\n\
|
||||
}\n" };
|
||||
|
||||
char fragment_osd[] = { "\
|
||||
%s\n\
|
||||
#define texture1D texture\n\
|
||||
precision mediump float; \
|
||||
layout(location = 0) out vec4 out_color;\n\
|
||||
in vec2 texcoord0;\n\
|
||||
uniform sampler2D texture0;\n\
|
||||
void main() {\n\
|
||||
vec4 color; \n\
|
||||
color = vec4(texture(texture0, texcoord0));\n\
|
||||
out_color = color;\n\
|
||||
}\n" };
|
||||
|
||||
char vertex[] = { "\
|
||||
%s\n\
|
||||
in vec2 vertex_position;\n\
|
||||
in vec2 vertex_texcoord0;\n\
|
||||
out vec2 texcoord0;\n\
|
||||
in vec2 vertex_texcoord1;\n\
|
||||
out vec2 texcoord1;\n\
|
||||
void main() {\n\
|
||||
gl_Position = vec4(vertex_position, 1.0, 1.0);\n\
|
||||
texcoord0 = vertex_texcoord0;\n\
|
||||
texcoord1 = vertex_texcoord1;\n\
|
||||
}\n" };
|
||||
|
||||
char fragment[] = { "\
|
||||
%s\n\
|
||||
#define texture1D texture\n\
|
||||
#define texture3D texture\n\
|
||||
precision mediump float; \
|
||||
layout(location = 0) out vec4 out_color;\n\
|
||||
in vec2 texcoord0;\n\
|
||||
in vec2 texcoord1;\n\
|
||||
uniform mat3 colormatrix;\n\
|
||||
uniform vec3 colormatrix_c;\n\
|
||||
uniform sampler2D texture0;\n\
|
||||
uniform sampler2D texture1;\n\
|
||||
//#define LUT_POS(x, lut_size) mix(0.5 / (lut_size), 1.0 - 0.5 / (lut_size), (x))\n\
|
||||
void main() {\n\
|
||||
vec4 color; // = vec4(0.0, 0.0, 0.0, 1.0);\n\
|
||||
color.r = 1.000000 * vec4(texture(texture0, texcoord0)).r;\n\
|
||||
color.gb = 1.000000 * vec4(texture(texture1, texcoord1)).rg;\n\
|
||||
// color conversion\n\
|
||||
color.rgb = mat3(colormatrix) * color.rgb + colormatrix_c;\n\
|
||||
color.a = 1.0;\n\
|
||||
// color mapping\n\
|
||||
out_color = color;\n\
|
||||
}\n" };
|
||||
|
||||
char fragment_bt2100[] = { "\
|
||||
%s\n \
|
||||
#define texture1D texture\n\
|
||||
#define texture3D texture\n\
|
||||
precision mediump float; \
|
||||
layout(location = 0) out vec4 out_color;\n\
|
||||
in vec2 texcoord0;\n\
|
||||
in vec2 texcoord1;\n\
|
||||
uniform mat3 colormatrix;\n\
|
||||
uniform vec3 colormatrix_c;\n\
|
||||
uniform mat3 cms_matrix;\n\
|
||||
uniform sampler2D texture0;\n\
|
||||
uniform sampler2D texture1;\n\
|
||||
//#define LUT_POS(x, lut_size) mix(0.5 / (lut_size), 1.0 - 0.5 / (lut_size), (x))\n\
|
||||
void main() {\n\
|
||||
vec4 color; // = vec4(0.0, 0.0, 0.0, 1.0);\n\
|
||||
color.r = 1.003906 * vec4(texture(texture0, texcoord0)).r;\n\
|
||||
color.gb = 1.003906 * vec4(texture(texture1, texcoord1)).rg;\n\
|
||||
// color conversion\n\
|
||||
color.rgb = mat3(colormatrix) * color.rgb + colormatrix_c;\n\
|
||||
color.a = 1.0;\n\
|
||||
// color mapping\n\
|
||||
color.rgb = clamp(color.rgb, 0.0, 1.0);\n\
|
||||
color.rgb = pow(color.rgb, vec3(2.4));\n\
|
||||
color.rgb = cms_matrix * color.rgb;\n\
|
||||
color.rgb = clamp(color.rgb, 0.0, 1.0);\n\
|
||||
color.rgb = pow(color.rgb, vec3(1.0/2.4));\n\
|
||||
out_color = color;\n\
|
||||
}\n" };
|
||||
|
||||
|
||||
/* Color conversion matrix: RGB = m * YUV + c
|
||||
* m is in row-major matrix, with m[row][col], e.g.:
|
||||
* [ a11 a12 a13 ] float m[3][3] = { { a11, a12, a13 },
|
||||
@@ -205,37 +38,49 @@ struct mp_mat
|
||||
// YUV input limited range (16-235 for luma, 16-240 for chroma)
|
||||
// ITU-R BT.601 (SD)
|
||||
struct mp_cmat yuv_bt601 = { {{1.164384, 1.164384, 1.164384},
|
||||
{0.00000, -0.391762, 2.017232},
|
||||
{1.596027, -0.812968, 0.000000}},
|
||||
{-0.874202, 0.531668, -1.085631}
|
||||
{0.00000, -0.391762, 2.017232},
|
||||
{1.596027, -0.812968, 0.000000}},
|
||||
{-0.874202, 0.531668, -1.085631}
|
||||
};
|
||||
|
||||
// ITU-R BT.709 (HD)
|
||||
struct mp_cmat yuv_bt709 = { {{1.164384, 1.164384, 1.164384},
|
||||
{0.00000, -0.213249, 2.112402},
|
||||
{1.792741, -0.532909, 0.000000}},
|
||||
{-0.972945, 0.301483, -1.133402}
|
||||
{0.00000, -0.213249, 2.112402},
|
||||
{1.792741, -0.532909, 0.000000}},
|
||||
{-0.972945, 0.301483, -1.133402}
|
||||
};
|
||||
|
||||
// ITU-R BT.2020 non-constant luminance system
|
||||
struct mp_cmat yuv_bt2020ncl = { {{1.164384, 1.164384, 1.164384},
|
||||
{0.00000, -0.187326, 2.141772},
|
||||
{1.678674, -0.650424, 0.000000}},
|
||||
{-0.915688, 0.347459, -1.148145}
|
||||
{0.00000, -0.187326, 2.141772},
|
||||
{1.678674, -0.650424, 0.000000}},
|
||||
{-0.915688, 0.347459, -1.148145}
|
||||
};
|
||||
|
||||
// ITU-R BT.2020 constant luminance system
|
||||
struct mp_cmat yuv_bt2020cl = { {{0.0000, 1.164384, 0.000000},
|
||||
{0.00000, 0.000000, 1.138393},
|
||||
{1.138393, 0.000000, 0.000000}},
|
||||
{-0.571429, -0.073059, -0.571429}
|
||||
{0.00000, 0.000000, 1.138393},
|
||||
{1.138393, 0.000000, 0.000000}},
|
||||
{-0.571429, -0.073059, -0.571429}
|
||||
};
|
||||
|
||||
float cms_matrix[3][3] = { {1.660497, -0.124547, -0.018154},
|
||||
{-0.587657, 1.132895, -0.100597},
|
||||
{-0.072840, -0.008348, 1.118751}
|
||||
{-0.587657, 1.132895, -0.100597},
|
||||
{-0.072840, -0.008348, 1.118751}
|
||||
};
|
||||
|
||||
// Common constants for SMPTE ST.2084 (PQ)
|
||||
static const float PQ_M1 = 2610. / 4096 * 1. / 4,
|
||||
PQ_M2 = 2523. / 4096 * 128,
|
||||
PQ_C1 = 3424. / 4096,
|
||||
PQ_C2 = 2413. / 4096 * 32,
|
||||
PQ_C3 = 2392. / 4096 * 32;
|
||||
|
||||
// Common constants for ARIB STD-B67 (HLG)
|
||||
static const float HLG_A = 0.17883277,
|
||||
HLG_B = 0.28466892,
|
||||
HLG_C = 0.55991073;
|
||||
|
||||
struct gl_vao_entry
|
||||
{
|
||||
// used for shader / glBindAttribLocation
|
||||
@@ -272,16 +117,61 @@ static const struct gl_vao_entry vertex_vao[] = {
|
||||
{0}
|
||||
};
|
||||
|
||||
#define GLSL(...) pl_shader_append(__VA_ARGS__)
|
||||
#define GLSLV(...) pl_shader_append_v(__VA_ARGS__)
|
||||
|
||||
char sh[SHADER_LENGTH];
|
||||
char shv[SHADER_LENGTH];
|
||||
|
||||
GL_init()
|
||||
{
|
||||
sh[0] = 0;
|
||||
}
|
||||
|
||||
GLV_init()
|
||||
{
|
||||
shv[0] = 0;
|
||||
}
|
||||
|
||||
pl_shader_append(const char *fmt, ...)
|
||||
{
|
||||
char temp[1000];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsprintf(temp, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (strlen(sh) + strlen(temp) > SHADER_LENGTH)
|
||||
Fatal(_("Shaderlenght fault\n"));
|
||||
strcat(sh, temp);
|
||||
|
||||
}
|
||||
|
||||
pl_shader_append_v(const char *fmt, ...)
|
||||
{
|
||||
char temp[1000];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsprintf(temp, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (strlen(shv) + strlen(temp) > SHADER_LENGTH)
|
||||
Fatal(_("Shaderlenght fault\n"));
|
||||
strcat(shv, temp);
|
||||
|
||||
}
|
||||
|
||||
static void compile_attach_shader(GLuint program, GLenum type, const char *source)
|
||||
{
|
||||
GLuint shader;
|
||||
GLint status, log_length;
|
||||
GLint status = 1234, log_length;
|
||||
char log[4000];
|
||||
GLsizei len;
|
||||
char *buffer = (char *) malloc(1000);
|
||||
sprintf(buffer,source,gl_version);
|
||||
|
||||
shader = glCreateShader(type);
|
||||
glShaderSource(shader, 1, (const GLchar **)&buffer, NULL);
|
||||
glShaderSource(shader, 1, (const GLchar **)&source, NULL); // &buffer, NULL);
|
||||
glCompileShader(shader);
|
||||
status = 0;
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
|
||||
@@ -293,7 +183,7 @@ static void compile_attach_shader(GLuint program, GLenum type, const char *sourc
|
||||
|
||||
glAttachShader(program, shader);
|
||||
glDeleteShader(shader);
|
||||
free(buffer);
|
||||
|
||||
}
|
||||
|
||||
static void link_shader(GLuint program)
|
||||
@@ -313,14 +203,43 @@ static GLuint sc_generate_osd(GLuint gl_prog)
|
||||
|
||||
Debug(3, "vor create osd\n");
|
||||
gl_prog = glCreateProgram();
|
||||
|
||||
GL_init();
|
||||
GLSL("%s\n", gl_version);
|
||||
GLSL("in vec2 vertex_position;\n");
|
||||
GLSL("in vec2 vertex_texcoord0;\n");
|
||||
GLSL("out vec2 texcoord0;\n");
|
||||
GLSL("void main() {\n");
|
||||
GLSL("gl_Position = vec4(vertex_position, 1.0, 1.0);\n");
|
||||
GLSL("texcoord0 = vertex_texcoord0;\n");
|
||||
GLSL("}\n");
|
||||
|
||||
Debug(3, "vor compile vertex osd\n");
|
||||
compile_attach_shader(gl_prog, GL_VERTEX_SHADER, vertex_osd);
|
||||
compile_attach_shader(gl_prog, GL_VERTEX_SHADER, sh); // vertex_osd);
|
||||
GL_init();
|
||||
GLSL("%s\n", gl_version);
|
||||
GLSL("#define texture1D texture\n");
|
||||
GLSL("precision mediump float; \n");
|
||||
GLSL("layout(location = 0) out vec4 out_color;\n");
|
||||
GLSL("in vec2 texcoord0;\n");
|
||||
GLSL("uniform sampler2D texture0;\n");
|
||||
GLSL("void main() {\n");
|
||||
GLSL("vec4 color; \n");
|
||||
GLSL("color = vec4(texture(texture0, texcoord0));\n");
|
||||
#ifdef GAMMA
|
||||
GLSL("// delinearize gamma \n");
|
||||
GLSL("color.rgb = clamp(color.rgb, 0.0, 1.0); \n"); // delinearize gamma
|
||||
GLSL("color.rgb = pow(color.rgb, vec3(2.4)); \n");
|
||||
#endif
|
||||
GLSL("out_color = color;\n");
|
||||
GLSL("}\n");
|
||||
Debug(3, "vor compile fragment osd \n");
|
||||
compile_attach_shader(gl_prog, GL_FRAGMENT_SHADER, fragment_osd);
|
||||
compile_attach_shader(gl_prog, GL_FRAGMENT_SHADER, sh); //fragment_osd);
|
||||
glBindAttribLocation(gl_prog, 0, "vertex_position");
|
||||
glBindAttribLocation(gl_prog, 1, "vertex_texcoord0");
|
||||
|
||||
link_shader(gl_prog);
|
||||
|
||||
return gl_prog;
|
||||
}
|
||||
|
||||
@@ -333,41 +252,135 @@ static GLuint sc_generate(GLuint gl_prog, enum AVColorSpace colorspace)
|
||||
float *m, *c, *cms;
|
||||
char *frag;
|
||||
|
||||
GL_init();
|
||||
GLSL("%s\n", gl_version);
|
||||
GLSL("in vec2 vertex_position; \n");
|
||||
GLSL("in vec2 vertex_texcoord0; \n");
|
||||
GLSL("out vec2 texcoord0; \n");
|
||||
GLSL("in vec2 vertex_texcoord1; \n");
|
||||
GLSL("out vec2 texcoord1; \n");
|
||||
if (Planes == 3) {
|
||||
GLSL("in vec2 vertex_texcoord2; \n");
|
||||
GLSL("out vec2 texcoord2; \n");
|
||||
}
|
||||
GLSL("void main() { \n");
|
||||
GLSL("gl_Position = vec4(vertex_position, 1.0, 1.0);\n");
|
||||
GLSL("texcoord0 = vertex_texcoord0; \n");
|
||||
GLSL("texcoord1 = vertex_texcoord1; \n");
|
||||
if (Planes == 3) {
|
||||
GLSL("texcoord2 = vertex_texcoord1; \n"); // texcoord1 ist hier richtig
|
||||
}
|
||||
GLSL("} \n");
|
||||
|
||||
Debug(3, "vor create\n");
|
||||
gl_prog = glCreateProgram();
|
||||
Debug(3, "vor compile vertex\n");
|
||||
// printf("%s",sh);
|
||||
compile_attach_shader(gl_prog, GL_VERTEX_SHADER, sh);
|
||||
|
||||
switch (colorspace) {
|
||||
case AVCOL_SPC_RGB:
|
||||
m = &yuv_bt601.m[0][0];
|
||||
c = &yuv_bt601.c[0];
|
||||
frag = Planes == 3?fragment_3:fragment;
|
||||
Debug(3, "BT601 Colorspace used\n");
|
||||
break;
|
||||
case AVCOL_SPC_BT709:
|
||||
case AVCOL_SPC_UNSPECIFIED: // comes with UHD
|
||||
m = &yuv_bt709.m[0][0];
|
||||
c = &yuv_bt709.c[0];
|
||||
frag = Planes==3?fragment_3:fragment;
|
||||
Debug(3, "BT709 Colorspace used\n");
|
||||
break;
|
||||
case AVCOL_SPC_BT2020_NCL:
|
||||
m = &yuv_bt2020ncl.m[0][0];
|
||||
c = &yuv_bt2020ncl.c[0];
|
||||
cms = &cms_matrix[0][0];
|
||||
frag = Planes == 3?fragment_bt2100_3:fragment_bt2100;
|
||||
Debug(3, "BT2020NCL Colorspace used\n");
|
||||
break;
|
||||
default: // fallback
|
||||
m = &yuv_bt709.m[0][0];
|
||||
c = &yuv_bt709.c[0];
|
||||
frag = Planes==3?fragment_3:fragment;
|
||||
Debug(3, "default BT709 Colorspace used %d\n", colorspace);
|
||||
break;
|
||||
}
|
||||
|
||||
Debug(3, "vor create\n");
|
||||
gl_prog = glCreateProgram();
|
||||
Debug(3, "vor compile vertex\n");
|
||||
compile_attach_shader(gl_prog, GL_VERTEX_SHADER, Planes==3?vertex_3:vertex);
|
||||
GL_init();
|
||||
|
||||
GLSL("%s\n", gl_version);
|
||||
GLSL("precision mediump float; \n");
|
||||
GLSL("layout(location = 0) out vec4 out_color;\n");
|
||||
GLSL("in vec2 texcoord0; \n");
|
||||
GLSL("in vec2 texcoord1; \n");
|
||||
if (Planes == 3)
|
||||
GLSL("in vec2 texcoord2; \n");
|
||||
GLSL("uniform mat3 colormatrix; \n");
|
||||
GLSL("uniform vec3 colormatrix_c; \n");
|
||||
if (colorspace == AVCOL_SPC_BT2020_NCL)
|
||||
GLSL("uniform mat3 cms_matrix;\n");
|
||||
GLSL("uniform sampler2D texture0; \n");
|
||||
GLSL("uniform sampler2D texture1; \n");
|
||||
if (Planes == 3)
|
||||
GLSL("uniform sampler2D texture2; \n");
|
||||
GLSL("void main() { \n");
|
||||
GLSL("vec4 color; \n");
|
||||
|
||||
if (colorspace == AVCOL_SPC_BT2020_NCL) {
|
||||
GLSL("color.r = 1.003906 * vec4(texture(texture0, texcoord0)).r; \n");
|
||||
if (Planes == 3) {
|
||||
GLSL("color.g = 1.003906 * vec4(texture(texture1, texcoord1)).r; \n");
|
||||
GLSL("color.b = 1.003906 * vec4(texture(texture2, texcoord2)).r; \n");
|
||||
} else {
|
||||
GLSL("color.gb = 1.003906 * vec4(texture(texture1, texcoord1)).rg;\n");
|
||||
}
|
||||
GLSL("// color conversion\n");
|
||||
GLSL("color.rgb = mat3(colormatrix) * color.rgb + colormatrix_c; \n");
|
||||
GLSL("color.a = 1.0; \n");
|
||||
|
||||
GLSL("// pl_shader_linearize \n");
|
||||
GLSL("color.rgb = max(color.rgb, 0.0); \n");
|
||||
// GLSL("color.rgb = clamp(color.rgb, 0.0, 1.0); \n");
|
||||
// GLSL("color.rgb = pow(color.rgb, vec3(2.4)); \n");
|
||||
// GLSL("color.rgb = mix(vec3(4.0) * color.rgb * color.rgb,exp((color.rgb - vec3(%f)) * vec3(1.0/%f)) + vec3(%f),bvec3(lessThan(vec3(0.5), color.rgb)));\n",HLG_C, HLG_A, HLG_B);
|
||||
GLSL("color.rgb = mix(vec3(4.0) * color.rgb * color.rgb,exp((color.rgb - vec3(0.55991073)) * vec3(1.0/0.17883277)) + vec3(0.28466892), bvec3(lessThan(vec3(0.5), color.rgb)));\n");
|
||||
GLSL("// color mapping \n");
|
||||
GLSL("color.rgb = cms_matrix * color.rgb; \n");
|
||||
#ifndef GAMMA
|
||||
GLSL("// pl_shader_delinearize \n");
|
||||
GLSL("color.rgb = max(color.rgb, 0.0); \n");
|
||||
// GLSL("color.rgb = clamp(color.rgb, 0.0, 1.0); \n");
|
||||
// GLSL("color.rgb = pow(color.rgb, vec3(1.0/2.4)); \n");
|
||||
GLSL("color.rgb = mix(vec3(0.5) * sqrt(color.rgb), vec3(0.17883277) * log(color.rgb - vec3(0.28466892)) + vec3(0.55991073), bvec3(lessThan(vec3(1.0), color.rgb))); \n");
|
||||
|
||||
#endif
|
||||
GLSL("out_color = color; \n");
|
||||
GLSL("} \n");
|
||||
} else {
|
||||
|
||||
GLSL("color.r = 1.000000 * vec4(texture(texture0, texcoord0)).r; \n");
|
||||
if (Planes == 3) {
|
||||
GLSL("color.g = 1.000000 * vec4(texture(texture1, texcoord1)).r;\n");
|
||||
GLSL("color.b = 1.000000 * vec4(texture(texture2, texcoord2)).r;\n");
|
||||
} else {
|
||||
GLSL("color.gb = 1.000000 * vec4(texture(texture1, texcoord1)).rg; \n");
|
||||
}
|
||||
GLSL("// color conversion \n");
|
||||
GLSL("color.rgb = mat3(colormatrix) * color.rgb + colormatrix_c; \n");
|
||||
GLSL("color.a = 1.0; \n");
|
||||
|
||||
GLSL("// linearize gamma \n");
|
||||
GLSL("color.rgb = clamp(color.rgb, 0.0, 1.0); \n"); // linearize gamma
|
||||
GLSL("color.rgb = pow(color.rgb, vec3(2.4)); \n");
|
||||
#ifndef GAMMA
|
||||
GLSL("// delinearize gamma to sRGB \n");
|
||||
GLSL("color.rgb = max(color.rgb, 0.0); \n");
|
||||
GLSL("color.rgb = mix(color.rgb * vec3(12.92), vec3(1.055) * pow(color.rgb, vec3(1.0/2.4)) - vec3(0.055), bvec3(lessThanEqual(vec3(0.0031308), color.rgb))); \n");
|
||||
#endif
|
||||
GLSL("// color mapping \n");
|
||||
GLSL("out_color = color; \n");
|
||||
GLSL("} \n");
|
||||
}
|
||||
//printf(">%s<",sh);
|
||||
Debug(3, "vor compile fragment\n");
|
||||
compile_attach_shader(gl_prog, GL_FRAGMENT_SHADER, frag);
|
||||
compile_attach_shader(gl_prog, GL_FRAGMENT_SHADER, sh);
|
||||
glBindAttribLocation(gl_prog, 0, "vertex_position");
|
||||
|
||||
for (n = 0; n < 6; n++) {
|
||||
|
222
shaders/KrigBilateral.glsl
Normal file
222
shaders/KrigBilateral.glsl
Normal file
@@ -0,0 +1,222 @@
|
||||
// KrigBilateral by Shiandow
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3.0 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library.
|
||||
|
||||
//!HOOK CHROMA
|
||||
//!BIND HOOKED
|
||||
//!BIND LUMA
|
||||
//!SAVE LOWRES_Y
|
||||
//!WIDTH LUMA.w
|
||||
//!WHEN CHROMA.w LUMA.w <
|
||||
//!DESC KrigBilateral Downscaling Y pass 1
|
||||
|
||||
#define offset vec2(0,0)
|
||||
|
||||
#define axis 1
|
||||
|
||||
#define Kernel(x) dot(vec3(0.42659, -0.49656, 0.076849), cos(vec3(0, 1, 2) * acos(-1.) * (x + 1.)))
|
||||
|
||||
vec4 hook() {
|
||||
// Calculate bounds
|
||||
float low = ceil((LUMA_pos - CHROMA_pt) * LUMA_size - offset - 0.5)[axis];
|
||||
float high = floor((LUMA_pos + CHROMA_pt) * LUMA_size - offset - 0.5)[axis];
|
||||
|
||||
float W = 0.0;
|
||||
vec4 avg = vec4(0);
|
||||
vec2 pos = LUMA_pos;
|
||||
|
||||
for (float k = low; k <= high; k++) {
|
||||
pos[axis] = LUMA_pt[axis] * (k - offset[axis] + 0.5);
|
||||
float rel = (pos[axis] - LUMA_pos[axis])*CHROMA_size[axis];
|
||||
float w = Kernel(rel);
|
||||
|
||||
vec4 y = textureGrad(LUMA_raw, pos, vec2(0.0), vec2(0.0)).xxxx * LUMA_mul;
|
||||
y.y *= y.y;
|
||||
avg += w * y;
|
||||
W += w;
|
||||
}
|
||||
avg /= W;
|
||||
avg.y = abs(avg.y - pow(avg.x, 2.0));
|
||||
return avg;
|
||||
}
|
||||
|
||||
//!HOOK CHROMA
|
||||
//!BIND HOOKED
|
||||
//!BIND LOWRES_Y
|
||||
//!SAVE LOWRES_Y
|
||||
//!WHEN CHROMA.w LUMA.w <
|
||||
//!DESC KrigBilateral Downscaling Y pass 2
|
||||
|
||||
#define offset vec2(0,0)
|
||||
|
||||
#define axis 0
|
||||
|
||||
#define Kernel(x) dot(vec3(0.42659, -0.49656, 0.076849), cos(vec3(0, 1, 2) * acos(-1.) * (x + 1.)))
|
||||
|
||||
vec4 hook() {
|
||||
// Calculate bounds
|
||||
float low = ceil((LOWRES_Y_pos - CHROMA_pt) * LOWRES_Y_size - offset - 0.5)[axis];
|
||||
float high = floor((LOWRES_Y_pos + CHROMA_pt) * LOWRES_Y_size - offset - 0.5)[axis];
|
||||
|
||||
float W = 0.0;
|
||||
vec4 avg = vec4(0);
|
||||
vec2 pos = LOWRES_Y_pos;
|
||||
|
||||
for (float k = low; k <= high; k++) {
|
||||
pos[axis] = LOWRES_Y_pt[axis] * (k - offset[axis] + 0.5);
|
||||
float rel = (pos[axis] - LOWRES_Y_pos[axis])*CHROMA_size[axis];
|
||||
float w = Kernel(rel);
|
||||
|
||||
vec4 y = textureGrad(LOWRES_Y_raw, pos, vec2(0.0), vec2(0.0)).xxxx * LOWRES_Y_mul;
|
||||
y.y *= y.y;
|
||||
avg += w * y;
|
||||
W += w;
|
||||
}
|
||||
avg /= W;
|
||||
avg.y = abs(avg.y - pow(avg.x, 2.0)) + LOWRES_Y_texOff(0).y;
|
||||
return avg;
|
||||
}
|
||||
|
||||
//!HOOK CHROMA
|
||||
//!BIND HOOKED
|
||||
//!BIND LUMA
|
||||
//!BIND LOWRES_Y
|
||||
//!WIDTH LUMA.w
|
||||
//!HEIGHT LUMA.h
|
||||
//!WHEN CHROMA.w LUMA.w <
|
||||
//!OFFSET ALIGN
|
||||
//!DESC KrigBilateral Upscaling UV
|
||||
|
||||
// -- Convenience --
|
||||
#define sqr(x) dot(x,x)
|
||||
#define bitnoise 1.0/(2.0*255.0)
|
||||
#define noise 0.05//5.0*bitnoise
|
||||
#define chromaOffset vec2(0.0, 0.0)
|
||||
|
||||
// -- Window Size --
|
||||
#define taps 3
|
||||
#define even (float(taps) - 2.0 * floor(float(taps) / 2.0) == 0.0)
|
||||
#define minX int(1.0-ceil(float(taps)/2.0))
|
||||
#define maxX int(floor(float(taps)/2.0))
|
||||
|
||||
#define Kernel(x) (cos(acos(-1.0)*(x)/float(taps))) // Hann kernel
|
||||
|
||||
// -- Input processing --
|
||||
#define GetY(coord) LOWRES_Y_tex(LOWRES_Y_pt*(pos+coord+vec2(0.5))).xy
|
||||
#define GetUV(coord) CHROMA_tex(CHROMA_pt*(pos+coord+vec2(0.5))).xy
|
||||
|
||||
#define N (taps*taps - 1)
|
||||
|
||||
#define M(i,j) Mx[min(i,j)*N + max(i,j) - min(i,j)*(min(i,j)+1)/2]
|
||||
|
||||
#define C(i,j) (inversesqrt(1.0 + (X[i].y + X[j].y)/localVar) * exp(-0.5*(sqr(X[i].x - X[j].x)/(localVar + X[i].y + X[j].y) + sqr((coords[i] - coords[j])/radius))) + (X[i].x - y) * (X[j].x - y) / localVar)
|
||||
#define c(i) (inversesqrt(1.0 + X[i].y/localVar) * exp(-0.5*(sqr(X[i].x - y)/(localVar + X[i].y) + sqr((coords[i] - offset)/radius))))
|
||||
|
||||
vec4 hook() {
|
||||
vec2 pos = CHROMA_pos * HOOKED_size - chromaOffset - vec2(0.5);
|
||||
vec2 offset = pos - (even ? floor(pos) : round(pos));
|
||||
pos -= offset;
|
||||
|
||||
vec2 coords[N+1];
|
||||
vec4 X[N+1];
|
||||
float y = LUMA_texOff(0).x;
|
||||
vec4 total = vec4(0);
|
||||
|
||||
coords[0] = vec2(-1,-1); coords[1] = vec2(-1, 0); coords[2] = vec2(-1, 1);
|
||||
coords[3] = vec2( 0,-1); coords[4] = vec2( 0, 1); coords[5] = vec2( 1,-1);
|
||||
coords[6] = vec2( 1, 0); coords[7] = vec2( 1, 1); coords[8] = vec2( 0, 0);
|
||||
|
||||
for (int i=0; i<N+1; i++) {
|
||||
X[i] = vec4(GetY(coords[i]), GetUV(coords[i]));
|
||||
vec2 w = clamp(1.5 - abs(coords[i] - offset), 0.0, 1.0);
|
||||
total += w.x*w.y*vec4(X[i].x, pow(X[i].x, 2.0), X[i].y, 1.0);
|
||||
}
|
||||
total.xyz /= total.w;
|
||||
float localVar = sqr(noise) + abs(total.y - pow(total.x, 2.0)) + total.z;
|
||||
float radius = 1.0;
|
||||
|
||||
float Mx[N*(N+1)/2];
|
||||
float b[N];
|
||||
vec4 interp = X[N];
|
||||
|
||||
b[0] = c(0) - c(N) - C(0,N) + C(N,N); M(0, 0) = C(0,0) - C(0,N) - C(0,N) + C(N,N); M(0, 1) = C(0,1) - C(1,N) - C(0,N) + C(N,N); M(0, 2) = C(0,2) - C(2,N) - C(0,N) + C(N,N); M(0, 3) = C(0,3) - C(3,N) - C(0,N) + C(N,N); M(0, 4) = C(0,4) - C(4,N) - C(0,N) + C(N,N); M(0, 5) = C(0,5) - C(5,N) - C(0,N) + C(N,N); M(0, 6) = C(0,6) - C(6,N) - C(0,N) + C(N,N); M(0, 7) = C(0,7) - C(7,N) - C(0,N) + C(N,N);
|
||||
b[1] = c(1) - c(N) - C(1,N) + C(N,N); M(1, 1) = C(1,1) - C(1,N) - C(1,N) + C(N,N); M(1, 2) = C(1,2) - C(2,N) - C(1,N) + C(N,N); M(1, 3) = C(1,3) - C(3,N) - C(1,N) + C(N,N); M(1, 4) = C(1,4) - C(4,N) - C(1,N) + C(N,N); M(1, 5) = C(1,5) - C(5,N) - C(1,N) + C(N,N); M(1, 6) = C(1,6) - C(6,N) - C(1,N) + C(N,N); M(1, 7) = C(1,7) - C(7,N) - C(1,N) + C(N,N);
|
||||
b[2] = c(2) - c(N) - C(2,N) + C(N,N); M(2, 2) = C(2,2) - C(2,N) - C(2,N) + C(N,N); M(2, 3) = C(2,3) - C(3,N) - C(2,N) + C(N,N); M(2, 4) = C(2,4) - C(4,N) - C(2,N) + C(N,N); M(2, 5) = C(2,5) - C(5,N) - C(2,N) + C(N,N); M(2, 6) = C(2,6) - C(6,N) - C(2,N) + C(N,N); M(2, 7) = C(2,7) - C(7,N) - C(2,N) + C(N,N);
|
||||
b[3] = c(3) - c(N) - C(3,N) + C(N,N); M(3, 3) = C(3,3) - C(3,N) - C(3,N) + C(N,N); M(3, 4) = C(3,4) - C(4,N) - C(3,N) + C(N,N); M(3, 5) = C(3,5) - C(5,N) - C(3,N) + C(N,N); M(3, 6) = C(3,6) - C(6,N) - C(3,N) + C(N,N); M(3, 7) = C(3,7) - C(7,N) - C(3,N) + C(N,N);
|
||||
b[4] = c(4) - c(N) - C(4,N) + C(N,N); M(4, 4) = C(4,4) - C(4,N) - C(4,N) + C(N,N); M(4, 5) = C(4,5) - C(5,N) - C(4,N) + C(N,N); M(4, 6) = C(4,6) - C(6,N) - C(4,N) + C(N,N); M(4, 7) = C(4,7) - C(7,N) - C(4,N) + C(N,N);
|
||||
b[5] = c(5) - c(N) - C(5,N) + C(N,N); M(5, 5) = C(5,5) - C(5,N) - C(5,N) + C(N,N); M(5, 6) = C(5,6) - C(6,N) - C(5,N) + C(N,N); M(5, 7) = C(5,7) - C(7,N) - C(5,N) + C(N,N);
|
||||
b[6] = c(6) - c(N) - C(6,N) + C(N,N); M(6, 6) = C(6,6) - C(6,N) - C(6,N) + C(N,N); M(6, 7) = C(6,7) - C(7,N) - C(6,N) + C(N,N);
|
||||
b[7] = c(7) - c(N) - C(7,N) + C(N,N); M(7, 7) = C(7,7) - C(7,N) - C(7,N) + C(N,N);
|
||||
|
||||
b[1] -= b[0] * M(1, 0) / M(0, 0); M(1, 1) -= M(0, 1) * M(1, 0) / M(0, 0); M(1, 2) -= M(0, 2) * M(1, 0) / M(0, 0); M(1, 3) -= M(0, 3) * M(1, 0) / M(0, 0); M(1, 4) -= M(0, 4) * M(1, 0) / M(0, 0); M(1, 5) -= M(0, 5) * M(1, 0) / M(0, 0); M(1, 6) -= M(0, 6) * M(1, 0) / M(0, 0); M(1, 7) -= M(0, 7) * M(1, 0) / M(0, 0);
|
||||
b[2] -= b[0] * M(2, 0) / M(0, 0); M(2, 2) -= M(0, 2) * M(2, 0) / M(0, 0); M(2, 3) -= M(0, 3) * M(2, 0) / M(0, 0); M(2, 4) -= M(0, 4) * M(2, 0) / M(0, 0); M(2, 5) -= M(0, 5) * M(2, 0) / M(0, 0); M(2, 6) -= M(0, 6) * M(2, 0) / M(0, 0); M(2, 7) -= M(0, 7) * M(2, 0) / M(0, 0);
|
||||
b[3] -= b[0] * M(3, 0) / M(0, 0); M(3, 3) -= M(0, 3) * M(3, 0) / M(0, 0); M(3, 4) -= M(0, 4) * M(3, 0) / M(0, 0); M(3, 5) -= M(0, 5) * M(3, 0) / M(0, 0); M(3, 6) -= M(0, 6) * M(3, 0) / M(0, 0); M(3, 7) -= M(0, 7) * M(3, 0) / M(0, 0);
|
||||
b[4] -= b[0] * M(4, 0) / M(0, 0); M(4, 4) -= M(0, 4) * M(4, 0) / M(0, 0); M(4, 5) -= M(0, 5) * M(4, 0) / M(0, 0); M(4, 6) -= M(0, 6) * M(4, 0) / M(0, 0); M(4, 7) -= M(0, 7) * M(4, 0) / M(0, 0);
|
||||
b[5] -= b[0] * M(5, 0) / M(0, 0); M(5, 5) -= M(0, 5) * M(5, 0) / M(0, 0); M(5, 6) -= M(0, 6) * M(5, 0) / M(0, 0); M(5, 7) -= M(0, 7) * M(5, 0) / M(0, 0);
|
||||
b[6] -= b[0] * M(6, 0) / M(0, 0); M(6, 6) -= M(0, 6) * M(6, 0) / M(0, 0); M(6, 7) -= M(0, 7) * M(6, 0) / M(0, 0);
|
||||
b[7] -= b[0] * M(7, 0) / M(0, 0); M(7, 7) -= M(0, 7) * M(7, 0) / M(0, 0);
|
||||
|
||||
b[2] -= b[1] * M(2, 1) / M(1, 1); M(2, 2) -= M(1, 2) * M(2, 1) / M(1, 1); M(2, 3) -= M(1, 3) * M(2, 1) / M(1, 1); M(2, 4) -= M(1, 4) * M(2, 1) / M(1, 1); M(2, 5) -= M(1, 5) * M(2, 1) / M(1, 1); M(2, 6) -= M(1, 6) * M(2, 1) / M(1, 1); M(2, 7) -= M(1, 7) * M(2, 1) / M(1, 1);
|
||||
b[3] -= b[1] * M(3, 1) / M(1, 1); M(3, 3) -= M(1, 3) * M(3, 1) / M(1, 1); M(3, 4) -= M(1, 4) * M(3, 1) / M(1, 1); M(3, 5) -= M(1, 5) * M(3, 1) / M(1, 1); M(3, 6) -= M(1, 6) * M(3, 1) / M(1, 1); M(3, 7) -= M(1, 7) * M(3, 1) / M(1, 1);
|
||||
b[4] -= b[1] * M(4, 1) / M(1, 1); M(4, 4) -= M(1, 4) * M(4, 1) / M(1, 1); M(4, 5) -= M(1, 5) * M(4, 1) / M(1, 1); M(4, 6) -= M(1, 6) * M(4, 1) / M(1, 1); M(4, 7) -= M(1, 7) * M(4, 1) / M(1, 1);
|
||||
b[5] -= b[1] * M(5, 1) / M(1, 1); M(5, 5) -= M(1, 5) * M(5, 1) / M(1, 1); M(5, 6) -= M(1, 6) * M(5, 1) / M(1, 1); M(5, 7) -= M(1, 7) * M(5, 1) / M(1, 1);
|
||||
b[6] -= b[1] * M(6, 1) / M(1, 1); M(6, 6) -= M(1, 6) * M(6, 1) / M(1, 1); M(6, 7) -= M(1, 7) * M(6, 1) / M(1, 1);
|
||||
b[7] -= b[1] * M(7, 1) / M(1, 1); M(7, 7) -= M(1, 7) * M(7, 1) / M(1, 1);
|
||||
|
||||
b[3] -= b[2] * M(3, 2) / M(2, 2); M(3, 3) -= M(2, 3) * M(3, 2) / M(2, 2); M(3, 4) -= M(2, 4) * M(3, 2) / M(2, 2); M(3, 5) -= M(2, 5) * M(3, 2) / M(2, 2); M(3, 6) -= M(2, 6) * M(3, 2) / M(2, 2); M(3, 7) -= M(2, 7) * M(3, 2) / M(2, 2);
|
||||
b[4] -= b[2] * M(4, 2) / M(2, 2); M(4, 4) -= M(2, 4) * M(4, 2) / M(2, 2); M(4, 5) -= M(2, 5) * M(4, 2) / M(2, 2); M(4, 6) -= M(2, 6) * M(4, 2) / M(2, 2); M(4, 7) -= M(2, 7) * M(4, 2) / M(2, 2);
|
||||
b[5] -= b[2] * M(5, 2) / M(2, 2); M(5, 5) -= M(2, 5) * M(5, 2) / M(2, 2); M(5, 6) -= M(2, 6) * M(5, 2) / M(2, 2); M(5, 7) -= M(2, 7) * M(5, 2) / M(2, 2);
|
||||
b[6] -= b[2] * M(6, 2) / M(2, 2); M(6, 6) -= M(2, 6) * M(6, 2) / M(2, 2); M(6, 7) -= M(2, 7) * M(6, 2) / M(2, 2);
|
||||
b[7] -= b[2] * M(7, 2) / M(2, 2); M(7, 7) -= M(2, 7) * M(7, 2) / M(2, 2);
|
||||
|
||||
b[4] -= b[3] * M(4, 3) / M(3, 3); M(4, 4) -= M(3, 4) * M(4, 3) / M(3, 3); M(4, 5) -= M(3, 5) * M(4, 3) / M(3, 3); M(4, 6) -= M(3, 6) * M(4, 3) / M(3, 3); M(4, 7) -= M(3, 7) * M(4, 3) / M(3, 3);
|
||||
b[5] -= b[3] * M(5, 3) / M(3, 3); M(5, 5) -= M(3, 5) * M(5, 3) / M(3, 3); M(5, 6) -= M(3, 6) * M(5, 3) / M(3, 3); M(5, 7) -= M(3, 7) * M(5, 3) / M(3, 3);
|
||||
b[6] -= b[3] * M(6, 3) / M(3, 3); M(6, 6) -= M(3, 6) * M(6, 3) / M(3, 3); M(6, 7) -= M(3, 7) * M(6, 3) / M(3, 3);
|
||||
b[7] -= b[3] * M(7, 3) / M(3, 3); M(7, 7) -= M(3, 7) * M(7, 3) / M(3, 3);
|
||||
|
||||
b[5] -= b[4] * M(5, 4) / M(4, 4); M(5, 5) -= M(4, 5) * M(5, 4) / M(4, 4); M(5, 6) -= M(4, 6) * M(5, 4) / M(4, 4); M(5, 7) -= M(4, 7) * M(5, 4) / M(4, 4);
|
||||
b[6] -= b[4] * M(6, 4) / M(4, 4); M(6, 6) -= M(4, 6) * M(6, 4) / M(4, 4); M(6, 7) -= M(4, 7) * M(6, 4) / M(4, 4);
|
||||
b[7] -= b[4] * M(7, 4) / M(4, 4); M(7, 7) -= M(4, 7) * M(7, 4) / M(4, 4);
|
||||
|
||||
b[6] -= b[5] * M(6, 5) / M(5, 5); M(6, 6) -= M(5, 6) * M(6, 5) / M(5, 5); M(6, 7) -= M(5, 7) * M(6, 5) / M(5, 5);
|
||||
b[7] -= b[5] * M(7, 5) / M(5, 5); M(7, 7) -= M(5, 7) * M(7, 5) / M(5, 5);
|
||||
|
||||
b[7] -= b[6] * M(7, 6) / M(6, 6); M(7, 7) -= M(6, 7) * M(7, 6) / M(6, 6);
|
||||
|
||||
b[N-1-0] /= M(N-1-0, N-1-0);
|
||||
interp += b[N-1-0] * (X[N-1-0] - X[N]);
|
||||
|
||||
b[N-1-1] -= M(N-1-1, 7) * b[7]; b[N-1-1] /= M(N-1-1, N-1-1);
|
||||
interp += b[N-1-1] * (X[N-1-1] - X[N]);
|
||||
|
||||
b[N-1-2] -= M(N-1-2, 6) * b[6]; b[N-1-2] -= M(N-1-2, 7) * b[7]; b[N-1-2] /= M(N-1-2, N-1-2);
|
||||
interp += b[N-1-2] * (X[N-1-2] - X[N]);
|
||||
|
||||
b[N-1-3] -= M(N-1-3, 5) * b[5]; b[N-1-3] -= M(N-1-3, 6) * b[6]; b[N-1-3] -= M(N-1-3, 7) * b[7]; b[N-1-3] /= M(N-1-3, N-1-3);
|
||||
interp += b[N-1-3] * (X[N-1-3] - X[N]);
|
||||
|
||||
b[N-1-4] -= M(N-1-4, 4) * b[4]; b[N-1-4] -= M(N-1-4, 5) * b[5]; b[N-1-4] -= M(N-1-4, 6) * b[6]; b[N-1-4] -= M(N-1-4, 7) * b[7]; b[N-1-4] /= M(N-1-4, N-1-4);
|
||||
interp += b[N-1-4] * (X[N-1-4] - X[N]);
|
||||
|
||||
b[N-1-5] -= M(N-1-5, 3) * b[3]; b[N-1-5] -= M(N-1-5, 4) * b[4]; b[N-1-5] -= M(N-1-5, 5) * b[5]; b[N-1-5] -= M(N-1-5, 6) * b[6]; b[N-1-5] -= M(N-1-5, 7) * b[7]; b[N-1-5] /= M(N-1-5, N-1-5);
|
||||
interp += b[N-1-5] * (X[N-1-5] - X[N]);
|
||||
|
||||
b[N-1-6] -= M(N-1-6, 2) * b[2]; b[N-1-6] -= M(N-1-6, 3) * b[3]; b[N-1-6] -= M(N-1-6, 4) * b[4]; b[N-1-6] -= M(N-1-6, 5) * b[5]; b[N-1-6] -= M(N-1-6, 6) * b[6]; b[N-1-6] -= M(N-1-6, 7) * b[7]; b[N-1-6] /= M(N-1-6, N-1-6);
|
||||
interp += b[N-1-6] * (X[N-1-6] - X[N]);
|
||||
|
||||
b[N-1-7] -= M(N-1-7, 1) * b[1]; b[N-1-7] -= M(N-1-7, 2) * b[2]; b[N-1-7] -= M(N-1-7, 3) * b[3]; b[N-1-7] -= M(N-1-7, 4) * b[4]; b[N-1-7] -= M(N-1-7, 5) * b[5]; b[N-1-7] -= M(N-1-7, 6) * b[6]; b[N-1-7] -= M(N-1-7, 7) * b[7]; b[N-1-7] /= M(N-1-7, N-1-7);
|
||||
interp += b[N-1-7] * (X[N-1-7] - X[N]);
|
||||
|
||||
return interp.zwxx;
|
||||
}
|
206
shaders/LumaSharpenHook.glsl
Normal file
206
shaders/LumaSharpenHook.glsl
Normal file
@@ -0,0 +1,206 @@
|
||||
// vim: set ft=glsl:
|
||||
|
||||
/*
|
||||
LumaSharpenHook 0.3
|
||||
|
||||
original hlsl by Christian Cann Schuldt Jensen ~ CeeJay.dk
|
||||
port to glsl by Anon
|
||||
|
||||
It blurs the original pixel with the surrounding pixels and then subtracts this blur to sharpen the image.
|
||||
It does this in luma to avoid color artifacts and allows limiting the maximum sharpning to avoid or lessen halo artifacts.
|
||||
|
||||
This is similar to using Unsharp Mask in Photoshop.
|
||||
*/
|
||||
|
||||
// -- Hooks --
|
||||
//!HOOK LUMA
|
||||
//!BIND HOOKED
|
||||
|
||||
|
||||
// -- Sharpening --
|
||||
#define sharp_strength 0.30 //[0.10 to 3.00] Strength of the sharpening
|
||||
|
||||
#define sharp_clamp 0.035 //[0.000 to 1.000] Limits maximum amount of sharpening a pixel recieves - Default is 0.035
|
||||
|
||||
// -- Advanced sharpening settings --
|
||||
#define pattern 2 //[1|2|3|4] Choose a sample pattern. 1 = Fast, 2 = Normal, 3 = Wider, 4 = Pyramid shaped.
|
||||
//[8|9] Experimental slower patterns. 8 = 9 tap 9 fetch gaussian, 9 = 9 tap 9 fetch high pass.
|
||||
|
||||
#define offset_bias 1.0 //[0.0 to 6.0] Offset bias adjusts the radius of the sampling pattern.
|
||||
|
||||
vec4 hook(){
|
||||
vec4 colorInput = LUMA_tex(LUMA_pos);
|
||||
|
||||
|
||||
//We are on luma plane: xyzw = [luma_val, 0.0, 0.0, 1.0]
|
||||
float ori = colorInput.x;
|
||||
|
||||
// -- Combining the strength and luma multipliers --
|
||||
float sharp_strength_luma = sharp_strength; //I'll be combining even more multipliers with it later on
|
||||
|
||||
float px = 1.0;
|
||||
float py = 1.0;
|
||||
|
||||
// Sampling patterns
|
||||
|
||||
// [ NW, , NE ] Each texture lookup (except ori)
|
||||
// [ ,ori, ] samples 4 pixels
|
||||
// [ SW, , SE ]
|
||||
|
||||
// -- Pattern 1 -- A (fast) 7 tap gaussian using only 2+1 texture fetches.
|
||||
#if pattern == 1
|
||||
|
||||
// -- Gaussian filter --
|
||||
// [ 1/9, 2/9, ] [ 1 , 2 , ]
|
||||
// [ 2/9, 8/9, 2/9] = [ 2 , 8 , 2 ]
|
||||
// [ , 2/9, 1/9] [ , 2 , 1 ]
|
||||
|
||||
px = (px / 3.0) * offset_bias;
|
||||
py = (py / 3.0) * offset_bias;
|
||||
|
||||
float blur_ori = LUMA_texOff(vec2(px,py)).x; // North West
|
||||
blur_ori += LUMA_texOff(vec2(-px,-py)).x; // South East
|
||||
|
||||
//blur_ori += LUMA_texOff(vec2(px,py)).x; // North East
|
||||
//blur_ori += LUMA_texOff(vec2(-px,-py)).x; // South West
|
||||
|
||||
blur_ori *= 0.5; //Divide by the number of texture fetches
|
||||
|
||||
sharp_strength_luma *= 1.5; // Adjust strength to aproximate the strength of pattern 2
|
||||
#endif
|
||||
|
||||
// -- Pattern 2 -- A 9 tap gaussian using 4+1 texture fetches.
|
||||
#if pattern == 2
|
||||
// -- Gaussian filter --
|
||||
// [ .25, .50, .25] [ 1 , 2 , 1 ]
|
||||
// [ .50, 1, .50] = [ 2 , 4 , 2 ]
|
||||
// [ .25, .50, .25] [ 1 , 2 , 1 ]
|
||||
|
||||
px = px * 0.5 * offset_bias;
|
||||
py = py * 0.5 * offset_bias;
|
||||
|
||||
float blur_ori = LUMA_texOff(vec2(px,-py)).x; // South East
|
||||
blur_ori += LUMA_texOff(vec2(-px,-py)).x; // South West
|
||||
blur_ori += LUMA_texOff(vec2(px,py)).x; // North East
|
||||
blur_ori += LUMA_texOff(vec2(-px,py)).x; // North West
|
||||
|
||||
blur_ori *= 0.25; // ( /= 4) Divide by the number of texture fetches
|
||||
#endif
|
||||
|
||||
// -- Pattern 3 -- An experimental 17 tap gaussian using 4+1 texture fetches.
|
||||
#if pattern == 3
|
||||
|
||||
// -- Gaussian filter --
|
||||
// [ , 4 , 6 , , ]
|
||||
// [ ,16 ,24 ,16 , 4 ]
|
||||
// [ 6 ,24 , ,24 , 6 ]
|
||||
// [ 4 ,16 ,24 ,16 , ]
|
||||
// [ , , 6 , 4 , ]
|
||||
|
||||
px = px * offset_bias;
|
||||
py = py * offset_bias;
|
||||
|
||||
float blur_ori = LUMA_texOff(vec2(0.4*px,-1.2*py)).x; // South South East
|
||||
blur_ori += LUMA_texOff(vec2(-1.2*px,-0.4*py)).x; // West South West
|
||||
blur_ori += LUMA_texOff(vec2(1.2*px,0.4*py)).x; // East North East
|
||||
blur_ori += LUMA_texOff(vec2(-0.4*px,1.2*py)).x; // North North West
|
||||
|
||||
blur_ori *= 0.25; // ( /= 4) Divide by the number of texture fetches
|
||||
|
||||
sharp_strength_luma *= 0.51;
|
||||
#endif
|
||||
|
||||
// -- Pattern 4 -- A 9 tap high pass (pyramid filter) using 4+1 texture fetches.
|
||||
#if pattern == 4
|
||||
// -- Gaussian filter --
|
||||
// [ .50, .50, .50] [ 1 , 1 , 1 ]
|
||||
// [ .50, , .50] = [ 1 , , 1 ]
|
||||
// [ .50, .50, .50] [ 1 , 1 , 1 ]
|
||||
|
||||
float blur_ori = LUMA_texOff(vec2(0.5 * px,-py * offset_bias)).x; // South South East
|
||||
blur_ori += LUMA_texOff(vec2(offset_bias * -px,0.5 * -py)).x; // West South West
|
||||
blur_ori += LUMA_texOff(vec2(offset_bias * px,0.5 * py)).x; // East North East
|
||||
blur_ori += LUMA_texOff(vec2(0.5 * -px,py * offset_bias)).x; // North North West
|
||||
|
||||
//blur_ori += (2.0 * ori); // Probably not needed. Only serves to lessen the effect.
|
||||
|
||||
blur_ori *= 0.25; //Divide by the number of texture fetches
|
||||
|
||||
sharp_strength_luma *= 0.666; // Adjust strength to aproximate the strength of pattern 2
|
||||
#endif
|
||||
|
||||
// -- Pattern 8 -- A (slower) 9 tap gaussian using 9 texture fetches.
|
||||
#if pattern == 8
|
||||
|
||||
// -- Gaussian filter --
|
||||
// [ 1 , 2 , 1 ]
|
||||
// [ 2 , 4 , 2 ]
|
||||
// [ 1 , 2 , 1 ]
|
||||
|
||||
px = px * offset_bias;
|
||||
py = py * offset_bias;
|
||||
|
||||
float blur_ori = LUMA_texOff(vec2(-px,py)).x; // North West
|
||||
blur_ori += LUMA_texOff(vec2(px,-py)).x; // South East
|
||||
blur_ori += LUMA_texOff(vec2(-px,-py)).x; // South West
|
||||
blur_ori += LUMA_texOff(vec2(px,py)).x; // North East
|
||||
|
||||
float blur_ori2 = LUMA_texOff(vec2(0.0,py)).x; // North
|
||||
blur_ori2 += LUMA_texOff(vec2(0.0,-py)).x; // South
|
||||
blur_ori2 += LUMA_texOff(vec2(-px,0.0)).x; // West
|
||||
blur_ori2 += LUMA_texOff(vec2(px,0.0)).x; // East
|
||||
blur_ori2 *= 2.0;
|
||||
|
||||
blur_ori += blur_ori2;
|
||||
blur_ori += (ori * 4.0); // Probably not needed. Only serves to lessen the effect.
|
||||
|
||||
// dot()s with gaussian strengths here?
|
||||
|
||||
blur_ori /= 16.0; //Divide by the number of texture fetches
|
||||
|
||||
sharp_strength_luma *= 0.75; // Adjust strength to aproximate the strength of pattern 2
|
||||
#endif
|
||||
|
||||
// -- Pattern 9 -- A (slower) 9 tap high pass using 9 texture fetches.
|
||||
#if pattern == 9
|
||||
|
||||
// -- Gaussian filter --
|
||||
// [ 1 , 1 , 1 ]
|
||||
// [ 1 , 1 , 1 ]
|
||||
// [ 1 , 1 , 1 ]
|
||||
|
||||
px = px * offset_bias;
|
||||
py = py * offset_bias;
|
||||
|
||||
float blur_ori = LUMA_texOff(vec2(-px,py)).x; // North West
|
||||
blur_ori += LUMA_texOff(vec2(px,-py)).x; // South East
|
||||
blur_ori += LUMA_texOff(vec2(-px,-py)).x; // South West
|
||||
blur_ori += LUMA_texOff(vec2(px,py)).x; // North East
|
||||
|
||||
blur_ori += ori; // Probably not needed. Only serves to lessen the effect.
|
||||
|
||||
blur_ori += LUMA_texOff(vec2(0.0,py)).x; // North
|
||||
blur_ori += LUMA_texOff(vec2(0.0,-py)).x; // South
|
||||
blur_ori += LUMA_texOff(vec2(-px,0.0)).x; // West
|
||||
blur_ori += LUMA_texOff(vec2(px,0.0)).x; // East
|
||||
|
||||
blur_ori /= 9.0; //Divide by the number of texture fetches
|
||||
|
||||
sharp_strength_luma *= (8.0/9.0); // Adjust strength to aproximate the strength of pattern 2
|
||||
#endif
|
||||
|
||||
// -- Calculate the sharpening --
|
||||
float sharp = ori - blur_ori; //Subtracting the blurred image from the original image
|
||||
|
||||
// -- Adjust strength of the sharpening and clamp it--
|
||||
float sharp_strength_luma_clamp = sharp_strength_luma / (2.0 * sharp_clamp); //Roll part of the clamp into the dot
|
||||
|
||||
float sharp_luma = clamp((sharp * sharp_strength_luma_clamp + 0.5), 0.0,1.0 ); //Calculate the luma, adjust the strength, scale up and clamp
|
||||
sharp_luma = (sharp_clamp * 2.0) * sharp_luma - sharp_clamp; //scale down
|
||||
|
||||
|
||||
// -- Combining the values to get the final sharpened pixel --
|
||||
|
||||
colorInput.x = colorInput.x + sharp_luma; // Add the sharpening to the input color.
|
||||
return clamp(colorInput, 0.0,1.0);
|
||||
}
|
246
shaders/adaptive-sharpen.glsl
Normal file
246
shaders/adaptive-sharpen.glsl
Normal file
@@ -0,0 +1,246 @@
|
||||
// Copyright (c) 2015-2018, bacondither
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer
|
||||
// in this position and unchanged.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
|
||||
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Adaptive sharpen - version 2018-04-14 - (requires ps >= 3.0)
|
||||
// Tuned for use post resize
|
||||
|
||||
//!HOOK SCALED
|
||||
//!BIND HOOKED
|
||||
//!SAVE ASSD
|
||||
//!COMPONENTS 2
|
||||
//!DESC adaptive-sharpen
|
||||
|
||||
//--------------------------------------- Settings ------------------------------------------------
|
||||
|
||||
#define curve_height 1.6 // Main control of sharpening strength [>0]
|
||||
// 0.3 <-> 2.0 is a reasonable range of values
|
||||
|
||||
// Defined values under this row are "optimal" DO NOT CHANGE IF YOU DO NOT KNOW WHAT YOU ARE DOING!
|
||||
|
||||
#define curveslope 0.5 // Sharpening curve slope, high edge values
|
||||
|
||||
#define L_overshoot 0.003 // Max light overshoot before compression [>0.001]
|
||||
#define L_compr_low 0.167 // Light compression, default (0.169=~9x)
|
||||
#define L_compr_high 0.334 // Light compression, surrounded by edges (0.337=~4x)
|
||||
|
||||
#define D_overshoot 0.009 // Max dark overshoot before compression [>0.001]
|
||||
#define D_compr_low 0.250 // Dark compression, default (0.253=~6x)
|
||||
#define D_compr_high 0.500 // Dark compression, surrounded by edges (0.504=~2.5x)
|
||||
|
||||
#define scale_lim 0.1 // Abs max change before compression (0.1=+-10%)
|
||||
#define scale_cs 0.056 // Compression slope above scale_lim
|
||||
|
||||
#define pm_p sat(1.0/curve_height) // Power mean p-value [>0-1.0]
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
// Soft limit
|
||||
#define soft_lim(v,s) ( (exp(2.0*min(abs(v), s*24.0)/s) - 1.0)/(exp(2.0*min(abs(v), s*24.0)/s) + 1.0)*s )
|
||||
|
||||
// Weighted power mean
|
||||
#define wpmean(a,b,c) ( pow((c*pow(abs(a), pm_p) + (1.0-c)*pow(b, pm_p)), (1.0/pm_p)) )
|
||||
|
||||
// Get destination pixel values
|
||||
#define get(x,y) ( HOOKED_texOff(vec2(x, y)).rgb )
|
||||
#define sat(x) ( clamp(x, 0.0, 1.0) )
|
||||
|
||||
// Colour to luma, fast approx gamma, avg of rec. 709 & 601 luma coeffs
|
||||
#define CtL(RGB) ( sqrt(dot(vec3(0.2558, 0.6511, 0.0931), pow(sat(RGB), vec3(2.0)))) )
|
||||
|
||||
// Center pixel diff
|
||||
#define mdiff(a,b,c,d,e,f,g) ( abs(luma[g]-luma[a]) + abs(luma[g]-luma[b]) \
|
||||
+ abs(luma[g]-luma[c]) + abs(luma[g]-luma[d]) \
|
||||
+ 0.5*(abs(luma[g]-luma[e]) + abs(luma[g]-luma[f])) )
|
||||
|
||||
#define b_diff(pix) ( abs(blur-c[pix]) )
|
||||
|
||||
vec4 hook() {
|
||||
|
||||
vec4 o = HOOKED_tex(HOOKED_pos);
|
||||
|
||||
// Get points, saturate colour data in c[0]
|
||||
// [ c22 ]
|
||||
// [ c24, c9, c23 ]
|
||||
// [ c21, c1, c2, c3, c18 ]
|
||||
// [ c19, c10, c4, c0, c5, c11, c16 ]
|
||||
// [ c20, c6, c7, c8, c17 ]
|
||||
// [ c15, c12, c14 ]
|
||||
// [ c13 ]
|
||||
vec3 c[25] = vec3[](sat(o.rgb), get(-1,-1), get( 0,-1), get( 1,-1), get(-1, 0),
|
||||
get( 1, 0), get(-1, 1), get( 0, 1), get( 1, 1), get( 0,-2),
|
||||
get(-2, 0), get( 2, 0), get( 0, 2), get( 0, 3), get( 1, 2),
|
||||
get(-1, 2), get( 3, 0), get( 2, 1), get( 2,-1), get(-3, 0),
|
||||
get(-2, 1), get(-2,-1), get( 0,-3), get( 1,-2), get(-1,-2));
|
||||
|
||||
// Blur, gauss 3x3
|
||||
vec3 blur = (2.0 * (c[2]+c[4]+c[5]+c[7]) + (c[1]+c[3]+c[6]+c[8]) + 4.0 * c[0]) / 16.0;
|
||||
|
||||
// Contrast compression, center = 0.5, scaled to 1/3
|
||||
float c_comp = sat(0.266666681f + 0.9*exp2(dot(blur, vec3(-7.4/3.0))));
|
||||
|
||||
// Edge detection
|
||||
// Relative matrix weights
|
||||
// [ 1 ]
|
||||
// [ 4, 5, 4 ]
|
||||
// [ 1, 5, 6, 5, 1 ]
|
||||
// [ 4, 5, 4 ]
|
||||
// [ 1 ]
|
||||
float edge = length( 1.38*b_diff(0)
|
||||
+ 1.15*(b_diff(2) + b_diff(4) + b_diff(5) + b_diff(7))
|
||||
+ 0.92*(b_diff(1) + b_diff(3) + b_diff(6) + b_diff(8))
|
||||
+ 0.23*(b_diff(9) + b_diff(10) + b_diff(11) + b_diff(12)) ) * c_comp;
|
||||
|
||||
// RGB to luma
|
||||
float c0_Y = CtL(c[0]);
|
||||
|
||||
float luma[25] = float[](c0_Y, CtL(c[1]), CtL(c[2]), CtL(c[3]), CtL(c[4]), CtL(c[5]), CtL(c[6]),
|
||||
CtL(c[7]), CtL(c[8]), CtL(c[9]), CtL(c[10]), CtL(c[11]), CtL(c[12]),
|
||||
CtL(c[13]), CtL(c[14]), CtL(c[15]), CtL(c[16]), CtL(c[17]), CtL(c[18]),
|
||||
CtL(c[19]), CtL(c[20]), CtL(c[21]), CtL(c[22]), CtL(c[23]), CtL(c[24]));
|
||||
|
||||
// Precalculated default squared kernel weights
|
||||
const vec3 w1 = vec3(0.5, 1.0, 1.41421356237); // 0.25, 1.0, 2.0
|
||||
const vec3 w2 = vec3(0.86602540378, 1.0, 0.54772255751); // 0.75, 1.0, 0.3
|
||||
|
||||
// Transition to a concave kernel if the center edge val is above thr
|
||||
vec3 dW = pow(mix( w1, w2, smoothstep( 0.3, 0.8, edge)), vec3(2.0));
|
||||
|
||||
float mdiff_c0 = 0.02 + 3.0*( abs(luma[0]-luma[2]) + abs(luma[0]-luma[4])
|
||||
+ abs(luma[0]-luma[5]) + abs(luma[0]-luma[7])
|
||||
+ 0.25*(abs(luma[0]-luma[1]) + abs(luma[0]-luma[3])
|
||||
+abs(luma[0]-luma[6]) + abs(luma[0]-luma[8])) );
|
||||
|
||||
// Use lower weights for pixels in a more active area relative to center pixel area
|
||||
// This results in narrower and less visible overshoots around sharp edges
|
||||
float weights[12] = float[](( min((mdiff_c0/mdiff(24, 21, 2, 4, 9, 10, 1)), dW.y) ),
|
||||
( dW.x ),
|
||||
( min((mdiff_c0/mdiff(23, 18, 5, 2, 9, 11, 3)), dW.y) ),
|
||||
( dW.x ),
|
||||
( dW.x ),
|
||||
( min((mdiff_c0/mdiff(4, 20, 15, 7, 10, 12, 6)), dW.y) ),
|
||||
( dW.x ),
|
||||
( min((mdiff_c0/mdiff(5, 7, 17, 14, 12, 11, 8)), dW.y) ),
|
||||
( min((mdiff_c0/mdiff(2, 24, 23, 22, 1, 3, 9)), dW.z) ),
|
||||
( min((mdiff_c0/mdiff(20, 19, 21, 4, 1, 6, 10)), dW.z) ),
|
||||
( min((mdiff_c0/mdiff(17, 5, 18, 16, 3, 8, 11)), dW.z) ),
|
||||
( min((mdiff_c0/mdiff(13, 15, 7, 14, 6, 8, 12)), dW.z) ));
|
||||
|
||||
weights[0] = (max(max((weights[8] + weights[9])/4.0, weights[0]), 0.25) + weights[0])/2.0;
|
||||
weights[2] = (max(max((weights[8] + weights[10])/4.0, weights[2]), 0.25) + weights[2])/2.0;
|
||||
weights[5] = (max(max((weights[9] + weights[11])/4.0, weights[5]), 0.25) + weights[5])/2.0;
|
||||
weights[7] = (max(max((weights[10] + weights[11])/4.0, weights[7]), 0.25) + weights[7])/2.0;
|
||||
|
||||
// Calculate the negative part of the laplace kernel
|
||||
float weightsum = 0.0;
|
||||
float neg_laplace = 0.0;
|
||||
|
||||
for (int pix = 0; pix < 12; ++pix)
|
||||
{
|
||||
neg_laplace += luma[pix+1]*weights[pix];
|
||||
weightsum += weights[pix];
|
||||
}
|
||||
|
||||
neg_laplace = neg_laplace / weightsum;
|
||||
|
||||
// Compute sharpening magnitude function
|
||||
float sharpen_val = (curve_height/(curve_height*curveslope*pow((edge), 3.5) + 0.625));
|
||||
|
||||
// Calculate sharpening diff and scale
|
||||
float sharpdiff = (c0_Y - neg_laplace)*(sharpen_val + 0.01);
|
||||
|
||||
// Calculate local near min & max, partial sort
|
||||
float temp;
|
||||
|
||||
for (int i1 = 0; i1 < 24; i1 += 2)
|
||||
{
|
||||
temp = luma[i1];
|
||||
luma[i1] = min(luma[i1], luma[i1+1]);
|
||||
luma[i1+1] = max(temp, luma[i1+1]);
|
||||
}
|
||||
|
||||
for (int i2 = 24; i2 > 0; i2 -= 2)
|
||||
{
|
||||
temp = luma[0];
|
||||
luma[0] = min(luma[0], luma[i2]);
|
||||
luma[i2] = max(temp, luma[i2]);
|
||||
|
||||
temp = luma[24];
|
||||
luma[24] = max(luma[24], luma[i2-1]);
|
||||
luma[i2-1] = min(temp, luma[i2-1]);
|
||||
}
|
||||
|
||||
for (int i1 = 1; i1 < 24-1; i1 += 2)
|
||||
{
|
||||
temp = luma[i1];
|
||||
luma[i1] = min(luma[i1], luma[i1+1]);
|
||||
luma[i1+1] = max(temp, luma[i1+1]);
|
||||
}
|
||||
|
||||
for (int i2 = 24-1; i2 > 1; i2 -= 2)
|
||||
{
|
||||
temp = luma[1];
|
||||
luma[1] = min(luma[1], luma[i2]);
|
||||
luma[i2] = max(temp, luma[i2]);
|
||||
|
||||
temp = luma[24-1];
|
||||
luma[24-1] = max(luma[24-1], luma[i2-1]);
|
||||
luma[i2-1] = min(temp, luma[i2-1]);
|
||||
}
|
||||
|
||||
float nmax = (max(luma[23], c0_Y)*3.0 + luma[24])/4.0;
|
||||
float nmin = (min(luma[1], c0_Y)*3.0 + luma[0])/4.0;
|
||||
|
||||
// Calculate tanh scale factors
|
||||
float min_dist = min(abs(nmax - c0_Y), abs(c0_Y - nmin));
|
||||
float pos_scale = min_dist + min(L_overshoot, 1.0001 - min_dist - c0_Y);
|
||||
float neg_scale = min_dist + min(D_overshoot, 0.0001 + c0_Y - min_dist);
|
||||
|
||||
pos_scale = min(pos_scale, scale_lim*(1.0 - scale_cs) + pos_scale*scale_cs);
|
||||
neg_scale = min(neg_scale, scale_lim*(1.0 - scale_cs) + neg_scale*scale_cs);
|
||||
|
||||
// Soft limited anti-ringing with tanh, wpmean to control compression slope
|
||||
sharpdiff = wpmean(max(sharpdiff, 0.0), soft_lim( max(sharpdiff, 0.0), pos_scale ), L_compr_low )
|
||||
- wpmean(min(sharpdiff, 0.0), soft_lim( min(sharpdiff, 0.0), neg_scale ), D_compr_low );
|
||||
|
||||
return vec4(sharpdiff, c0_Y, 0, 1);
|
||||
}
|
||||
|
||||
//!HOOK SCALED
|
||||
//!BIND HOOKED
|
||||
//!BIND ASSD
|
||||
//!DESC adaptive-sharpen equalization
|
||||
|
||||
#define video_level_out false // True to preserve BTB & WTW (minor summation error)
|
||||
// Normally it should be set to false
|
||||
#define SD(x,y) ASSD_texOff(vec2(x,y)).r
|
||||
|
||||
vec4 hook() {
|
||||
vec4 o = HOOKED_texOff(0);
|
||||
float sharpdiff = SD( 0, 0) - 0.6 * 0.25 * (SD(-0.5,-0.5) + SD( 0.5,-0.5) + SD(-0.5, 0.5) + SD( 0.5, 0.5));
|
||||
float c0_Y = ASSD_texOff(vec2(0)).g;
|
||||
float sharpdiff_lim = clamp(c0_Y + sharpdiff, 0.0, 1.0) - c0_Y;
|
||||
float satmul = (c0_Y + max(sharpdiff_lim*0.9, sharpdiff_lim)*1.03 + 0.03)/(c0_Y + 0.03);
|
||||
vec3 res = c0_Y + (sharpdiff_lim*3 + sharpdiff)/4 + (clamp(o.rgb, 0.0, 1.0) - c0_Y)*satmul;
|
||||
o.rgb = video_level_out == true ? res + o.rgb - clamp(o.rgb, 0.0, 1.0) : res;
|
||||
return o;
|
||||
}
|
41
shaders/filmgrain.glsl
Normal file
41
shaders/filmgrain.glsl
Normal file
@@ -0,0 +1,41 @@
|
||||
//!HOOK LUMA
|
||||
//!BIND HOOKED
|
||||
//!DESC gaussian film grain
|
||||
|
||||
#normal value is 0.05 changed for demo purposes
|
||||
#define INTENSITY 0.55
|
||||
|
||||
float permute(float x)
|
||||
{
|
||||
x = (34.0 * x + 1.0) * x;
|
||||
return fract(x * 1.0/289.0) * 289.0;
|
||||
}
|
||||
|
||||
float rand(inout float state)
|
||||
{
|
||||
state = permute(state);
|
||||
return fract(state * 1.0/41.0);
|
||||
}
|
||||
|
||||
vec4 hook()
|
||||
{
|
||||
vec3 m = vec3(HOOKED_pos, random) + vec3(1.0);
|
||||
float state = permute(permute(m.x) + m.y) + m.z;
|
||||
|
||||
const float a0 = 0.151015505647689;
|
||||
const float a1 = -0.5303572634357367;
|
||||
const float a2 = 1.365020122861334;
|
||||
const float b0 = 0.132089632343748;
|
||||
const float b1 = -0.7607324991323768;
|
||||
|
||||
float p = 0.95 * rand(state) + 0.025;
|
||||
float q = p - 0.5;
|
||||
float r = q * q;
|
||||
|
||||
float grain = q * (a2 + (a1 * r + a0) / (r*r + b1*r + b0));
|
||||
grain *= 0.255121822830526; // normalize to [-1,1)
|
||||
|
||||
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||
color.rgb += vec3(INTENSITY * grain);
|
||||
return color;
|
||||
}
|
147
softhdcuvid.cpp
147
softhdcuvid.cpp
@@ -61,7 +61,7 @@ extern "C"
|
||||
/// vdr-plugin version number.
|
||||
/// Makefile extracts the version number for generating the file name
|
||||
/// for the distribution archive.
|
||||
static const char *const VERSION = "3.0.0"
|
||||
static const char *const VERSION = "3.3.1"
|
||||
#ifdef GIT_REV
|
||||
"-GIT" GIT_REV
|
||||
#endif
|
||||
@@ -106,7 +106,7 @@ static int ConfigVideoBrightness; ///< config video brightness
|
||||
static int ConfigVideoContrast = 100; ///< config video contrast
|
||||
static int ConfigVideoSaturation = 100; ///< config video saturation
|
||||
static int ConfigVideoHue; ///< config video hue
|
||||
static int ConfigGamma; ///< config Gamma
|
||||
static int ConfigGamma=100; ///< config Gamma
|
||||
static int ConfigTargetColorSpace; ///< config Target Colrospace
|
||||
static int ConfigScalerTest; /// Test for Scalers
|
||||
static int ConfigColorBlindness;
|
||||
@@ -136,11 +136,6 @@ static int ConfigVideoCutTopBottom[RESOLUTIONS];
|
||||
/// config cut left and right pixels
|
||||
static int ConfigVideoCutLeftRight[RESOLUTIONS];
|
||||
|
||||
static int ConfigAutoCropEnabled; ///< auto crop detection enabled
|
||||
static int ConfigAutoCropInterval; ///< auto crop detection interval
|
||||
static int ConfigAutoCropDelay; ///< auto crop detection delay
|
||||
static int ConfigAutoCropTolerance; ///< auto crop detection tolerance
|
||||
|
||||
static int ConfigVideoAudioDelay; ///< config audio delay
|
||||
static char ConfigAudioDrift; ///< config audio drift
|
||||
static char ConfigAudioPassthrough; ///< config audio pass-through mask
|
||||
@@ -997,10 +992,6 @@ class cMenuSetupSoft:public cMenuSetupPage
|
||||
int CutTopBottom[RESOLUTIONS];
|
||||
int CutLeftRight[RESOLUTIONS];
|
||||
|
||||
int AutoCropInterval;
|
||||
int AutoCropDelay;
|
||||
int AutoCropTolerance;
|
||||
|
||||
int Audio;
|
||||
int AudioDelay;
|
||||
int AudioDrift;
|
||||
@@ -1096,10 +1087,10 @@ void cMenuSetupSoft::Create(void)
|
||||
"auto", "1920x1080", "1280x720", "custom",
|
||||
};
|
||||
static const char *const video_display_formats_4_3[] = {
|
||||
"pan&scan", "letterbox", "center cut-out",
|
||||
"pan&scan", "letterbox", "center cut-out", "original"
|
||||
};
|
||||
static const char *const video_display_formats_16_9[] = {
|
||||
"pan&scan", "pillarbox", "center cut-out",
|
||||
"pan&scan", "pillarbox", "center cut-out", "original"
|
||||
};
|
||||
#ifdef YADIF
|
||||
static const char *const deinterlace[] = {
|
||||
@@ -1133,7 +1124,7 @@ void cMenuSetupSoft::Create(void)
|
||||
static char *scalingtest[100];
|
||||
|
||||
if (scalers == 0) {
|
||||
scalingtest[0] = "Off";
|
||||
scalingtest[0] = (char *)"Off";
|
||||
for (scalers = 0; pl_named_filters[scalers].filter != NULL; scalers++) {
|
||||
scaling[scalers] = (char *)pl_named_filters[scalers].name;
|
||||
scalingtest[scalers + 1] = (char *)pl_named_filters[scalers].name;
|
||||
@@ -1182,9 +1173,9 @@ void cMenuSetupSoft::Create(void)
|
||||
Add(new cMenuEditBoolItem(tr("Enable Screensaver(DPMS) at black screen"), &EnableDPMSatBlackScreen,
|
||||
trVDR("no"), trVDR("yes")));
|
||||
#endif
|
||||
Add(new cMenuEditStraItem(trVDR("4:3 video display format"), &Video4to3DisplayFormat, 3,
|
||||
Add(new cMenuEditStraItem(trVDR("4:3 video display format"), &Video4to3DisplayFormat, 4,
|
||||
video_display_formats_4_3));
|
||||
Add(new cMenuEditStraItem(trVDR("16:9+other video display format"), &VideoOtherDisplayFormat, 3,
|
||||
Add(new cMenuEditStraItem(trVDR("16:9+other video display format"), &VideoOtherDisplayFormat, 4,
|
||||
video_display_formats_16_9));
|
||||
|
||||
#if 0
|
||||
@@ -1243,15 +1234,6 @@ void cMenuSetupSoft::Create(void)
|
||||
Add(new cMenuEditIntItem(tr("Cut left and right (pixel)"), &CutLeftRight[i], 0, 250));
|
||||
}
|
||||
}
|
||||
#ifdef USE_AUTOCROP
|
||||
//
|
||||
// auto-crop
|
||||
//
|
||||
Add(SeparatorItem(tr("Auto-crop")));
|
||||
Add(new cMenuEditIntItem(tr("Autocrop interval (frames)"), &AutoCropInterval, 0, 200, tr("off")));
|
||||
Add(new cMenuEditIntItem(tr("Autocrop delay (n * interval)"), &AutoCropDelay, 0, 200));
|
||||
Add(new cMenuEditIntItem(tr("Autocrop tolerance (pixel)"), &AutoCropTolerance, 0, 32));
|
||||
#endif
|
||||
}
|
||||
//
|
||||
// audio
|
||||
@@ -1261,12 +1243,15 @@ void cMenuSetupSoft::Create(void)
|
||||
if (Audio) {
|
||||
Add(new cMenuEditIntItem(tr("Audio/Video delay (ms)"), &AudioDelay, -1000, 1000));
|
||||
Add(new cMenuEditStraItem(tr("Audio drift correction"), &AudioDrift, 4, audiodrift));
|
||||
|
||||
Add(new cMenuEditBoolItem(tr("Pass-through default"), &AudioPassthroughDefault, trVDR("off"), trVDR("on")));
|
||||
Add(new cMenuEditBoolItem(tr("\040\040PCM pass-through"), &AudioPassthroughPCM, trVDR("no"), trVDR("yes")));
|
||||
Add(new cMenuEditBoolItem(tr("\040\040AC-3 pass-through"), &AudioPassthroughAC3, trVDR("no"), trVDR("yes")));
|
||||
Add(new cMenuEditBoolItem(tr("\040\040E-AC-3 pass-through"), &AudioPassthroughEAC3, trVDR("no"),
|
||||
trVDR("yes")));
|
||||
Add(new cMenuEditBoolItem(tr("Enable (E-)AC-3 (decoder) downmix"), &AudioDownmix, trVDR("no"), trVDR("yes")));
|
||||
if (AudioPassthroughDefault) {
|
||||
Add(new cMenuEditBoolItem(tr("\040\040PCM pass-through"), &AudioPassthroughPCM, trVDR("no"), trVDR("yes")));
|
||||
Add(new cMenuEditBoolItem(tr("\040\040AC-3 pass-through"), &AudioPassthroughAC3, trVDR("no"), trVDR("yes")));
|
||||
Add(new cMenuEditBoolItem(tr("\040\040E-AC-3 pass-through"), &AudioPassthroughEAC3, trVDR("no"),trVDR("yes")));
|
||||
} else {
|
||||
Add(new cMenuEditBoolItem(tr("Enable (E-)AC-3 (decoder) downmix"), &AudioDownmix, trVDR("no"), trVDR("yes")));
|
||||
}
|
||||
Add(new cMenuEditBoolItem(tr("Volume control"), &AudioSoftvol, tr("Hardware"), tr("Software")));
|
||||
Add(new cMenuEditBoolItem(tr("Enable normalize volume"), &AudioNormalize, trVDR("no"), trVDR("yes")));
|
||||
Add(new cMenuEditIntItem(tr(" Max normalize factor (/1000)"), &AudioMaxNormalize, 0, 10000));
|
||||
@@ -1322,10 +1307,12 @@ eOSState cMenuSetupSoft::ProcessKey(eKeys key)
|
||||
int old_osd_size;
|
||||
int old_resolution_shown[RESOLUTIONS];
|
||||
int i;
|
||||
int old_pass;
|
||||
|
||||
old_general = General;
|
||||
old_video = Video;
|
||||
old_audio = Audio;
|
||||
old_pass = AudioPassthroughDefault;
|
||||
#ifdef USE_PIP
|
||||
old_pip = Pip;
|
||||
#endif
|
||||
@@ -1340,6 +1327,7 @@ eOSState cMenuSetupSoft::ProcessKey(eKeys key)
|
||||
#ifdef USE_PIP
|
||||
|| old_pip != Pip
|
||||
#endif
|
||||
|| old_pass != AudioPassthroughDefault
|
||||
|| old_osd_size != OsdSize) {
|
||||
Create(); // update menu
|
||||
} else {
|
||||
@@ -1428,13 +1416,6 @@ cMenuSetupSoft::cMenuSetupSoft(void)
|
||||
CutTopBottom[i] = ConfigVideoCutTopBottom[i];
|
||||
CutLeftRight[i] = ConfigVideoCutLeftRight[i];
|
||||
}
|
||||
//
|
||||
// auto-crop
|
||||
//
|
||||
AutoCropInterval = ConfigAutoCropInterval;
|
||||
AutoCropDelay = ConfigAutoCropDelay;
|
||||
AutoCropTolerance = ConfigAutoCropTolerance;
|
||||
|
||||
//
|
||||
// audio
|
||||
//
|
||||
@@ -1591,12 +1572,6 @@ void cMenuSetupSoft::Store(void)
|
||||
VideoSetCutTopBottom(ConfigVideoCutTopBottom);
|
||||
VideoSetCutLeftRight(ConfigVideoCutLeftRight);
|
||||
|
||||
SetupStore("AutoCrop.Interval", ConfigAutoCropInterval = AutoCropInterval);
|
||||
SetupStore("AutoCrop.Delay", ConfigAutoCropDelay = AutoCropDelay);
|
||||
SetupStore("AutoCrop.Tolerance", ConfigAutoCropTolerance = AutoCropTolerance);
|
||||
VideoSetAutoCrop(ConfigAutoCropInterval, ConfigAutoCropDelay, ConfigAutoCropTolerance);
|
||||
ConfigAutoCropEnabled = ConfigAutoCropInterval != 0;
|
||||
|
||||
SetupStore("AudioDelay", ConfigVideoAudioDelay = AudioDelay);
|
||||
VideoSetAudioDelay(ConfigVideoAudioDelay);
|
||||
SetupStore("AudioDrift", ConfigAudioDrift = AudioDrift);
|
||||
@@ -2153,6 +2128,10 @@ void cSoftHdMenu::Create(void)
|
||||
int dropped;
|
||||
int counter;
|
||||
float frametime;
|
||||
int width, height;
|
||||
int color;
|
||||
int eotf;
|
||||
char *colorstr, *eotfstr;
|
||||
|
||||
current = Current(); // get current menu item index
|
||||
Clear(); // clear the menu
|
||||
@@ -2187,10 +2166,31 @@ void cSoftHdMenu::Create(void)
|
||||
#endif
|
||||
Add(new cOsdItem(NULL, osUnknown, false));
|
||||
Add(new cOsdItem(NULL, osUnknown, false));
|
||||
GetStats(&missed, &duped, &dropped, &counter, &frametime);
|
||||
GetStats(&missed, &duped, &dropped, &counter, &frametime, &width, &height, &color, &eotf);
|
||||
switch (color) {
|
||||
case AVCOL_SPC_RGB:
|
||||
colorstr = strdup("BT 601");
|
||||
eotfstr = strdup("BT 1886");
|
||||
break;
|
||||
case AVCOL_SPC_BT709:
|
||||
case AVCOL_SPC_UNSPECIFIED: // comes with UHD
|
||||
colorstr = strdup("BT 709");
|
||||
eotfstr = strdup("BT 1886");
|
||||
break;
|
||||
case AVCOL_SPC_BT2020_NCL:
|
||||
colorstr = strdup("BT 2020");
|
||||
eotfstr = strdup("HDR-HLG");
|
||||
break;
|
||||
default: // fallback
|
||||
colorstr = strdup("Fallback BT 709");
|
||||
eotfstr = strdup("BT 1886");
|
||||
break;
|
||||
}
|
||||
Add(new cOsdItem(cString::sprintf(tr(" Frames missed(%d) duped(%d) dropped(%d) total(%d)"), missed, duped, dropped,
|
||||
counter), osUnknown, false));
|
||||
Add(new cOsdItem(cString::sprintf(tr(" Frame Process time %2.2fms"), frametime), osUnknown, false));
|
||||
Add(new cOsdItem(cString::sprintf(tr(" Video %dx%d Color: %s Gamma: %s"), width, height, colorstr, eotfstr),
|
||||
osUnknown, false));
|
||||
// Add(new cOsdItem(cString::sprintf(tr(" Frame Process time %2.2fms"), frametime), osUnknown, false));
|
||||
SetCurrent(Get(current)); // restore selected menu entry
|
||||
Display(); // display build menu
|
||||
}
|
||||
@@ -2273,33 +2273,6 @@ static void HandleHotkey(int code)
|
||||
case 22: // toggle full screen
|
||||
VideoSetFullscreen(-1);
|
||||
break;
|
||||
case 23: // disable auto-crop
|
||||
ConfigAutoCropEnabled = 0;
|
||||
VideoSetAutoCrop(0, ConfigAutoCropDelay, ConfigAutoCropTolerance);
|
||||
Skins.QueueMessage(mtInfo, tr("auto-crop disabled and freezed"));
|
||||
break;
|
||||
case 24: // enable auto-crop
|
||||
ConfigAutoCropEnabled = 1;
|
||||
if (!ConfigAutoCropInterval) {
|
||||
ConfigAutoCropInterval = 50;
|
||||
}
|
||||
VideoSetAutoCrop(ConfigAutoCropInterval, ConfigAutoCropDelay, ConfigAutoCropTolerance);
|
||||
Skins.QueueMessage(mtInfo, tr("auto-crop enabled"));
|
||||
break;
|
||||
case 25: // toggle auto-crop
|
||||
ConfigAutoCropEnabled ^= 1;
|
||||
// no interval configured, use some default
|
||||
if (!ConfigAutoCropInterval) {
|
||||
ConfigAutoCropInterval = 50;
|
||||
}
|
||||
VideoSetAutoCrop(ConfigAutoCropEnabled * ConfigAutoCropInterval, ConfigAutoCropDelay,
|
||||
ConfigAutoCropTolerance);
|
||||
if (ConfigAutoCropEnabled) {
|
||||
Skins.QueueMessage(mtInfo, tr("auto-crop enabled"));
|
||||
} else {
|
||||
Skins.QueueMessage(mtInfo, tr("auto-crop disabled and freezed"));
|
||||
}
|
||||
break;
|
||||
case 30: // change 4:3 -> window mode
|
||||
case 31:
|
||||
case 32:
|
||||
@@ -3098,7 +3071,11 @@ bool cPluginSoftHdDevice::ProcessArgs(int argc, char *argv[])
|
||||
bool cPluginSoftHdDevice::Initialize(void)
|
||||
{
|
||||
// dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
||||
|
||||
#if defined PLACEBO
|
||||
const char *d;
|
||||
d = cPlugin::ConfigDirectory("shaders");
|
||||
strcpy(MyConfigDir,d);
|
||||
#endif
|
||||
MyDevice = new cSoftHdDevice();
|
||||
|
||||
return true;
|
||||
@@ -3269,7 +3246,6 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
|
||||
ConfigSuspendX11 = atoi(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!strcasecmp(name, "Video4to3DisplayFormat")) {
|
||||
Config4to3DisplayFormat = atoi(value);
|
||||
VideoSet4to3DisplayFormat(Config4to3DisplayFormat);
|
||||
@@ -3412,20 +3388,6 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
|
||||
}
|
||||
}
|
||||
|
||||
if (!strcasecmp(name, "AutoCrop.Interval")) {
|
||||
VideoSetAutoCrop(ConfigAutoCropInterval = atoi(value), ConfigAutoCropDelay, ConfigAutoCropTolerance);
|
||||
ConfigAutoCropEnabled = ConfigAutoCropInterval != 0;
|
||||
return true;
|
||||
}
|
||||
if (!strcasecmp(name, "AutoCrop.Delay")) {
|
||||
VideoSetAutoCrop(ConfigAutoCropInterval, ConfigAutoCropDelay = atoi(value), ConfigAutoCropTolerance);
|
||||
return true;
|
||||
}
|
||||
if (!strcasecmp(name, "AutoCrop.Tolerance")) {
|
||||
VideoSetAutoCrop(ConfigAutoCropInterval, ConfigAutoCropDelay, ConfigAutoCropTolerance = atoi(value));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!strcasecmp(name, "AudioDelay")) {
|
||||
VideoSetAudioDelay(ConfigVideoAudioDelay = atoi(value));
|
||||
return true;
|
||||
@@ -3435,11 +3397,11 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
|
||||
return true;
|
||||
}
|
||||
if (!strcasecmp(name, "AudioPassthrough")) {
|
||||
int i;
|
||||
int ii;
|
||||
|
||||
i = atoi(value);
|
||||
AudioPassthroughState = i > 0;
|
||||
ConfigAudioPassthrough = abs(i);
|
||||
ii = atoi(value);
|
||||
AudioPassthroughState = ii > 0;
|
||||
ConfigAudioPassthrough = abs(ii);
|
||||
if (AudioPassthroughState) {
|
||||
CodecSetAudioPassthrough(ConfigAudioPassthrough);
|
||||
} else {
|
||||
@@ -3681,7 +3643,6 @@ static const char *SVDRPHelpText[] = {
|
||||
" 12: toggle audio pass-through\n" " 13: decrease audio delay by 10ms\n"
|
||||
" 14: increase audio delay by 10ms\n" " 15: toggle ac3 mixdown\n"
|
||||
" 20: disable fullscreen\n\040 21: enable fullscreen\n" " 22: toggle fullscreen\n"
|
||||
" 23: disable auto-crop\n\040 24: enable auto-crop\n" " 25: toggle auto-crop\n"
|
||||
" 30: stretch 4:3 to display\n\040 31: pillar box 4:3 in display\n"
|
||||
" 32: center cut-out 4:3 to display\n" " 39: rotate 4:3 to display zoom mode\n"
|
||||
" 40: stretch other aspect ratios to display\n" " 41: letter box other aspect ratios in display\n"
|
||||
|
67
softhddev.c
67
softhddev.c
@@ -645,7 +645,7 @@ static void PesParse(PesDemux * pesdx, const uint8_t * data, int size, int is_st
|
||||
q = pesdx->Buffer + pesdx->Skip;
|
||||
n = pesdx->Index - pesdx->Skip;
|
||||
while (n >= 5) {
|
||||
int r;
|
||||
int r = 0;
|
||||
unsigned codec_id = AV_CODEC_ID_NONE;
|
||||
|
||||
// 4 bytes 0xFFExxxxx Mpeg audio
|
||||
@@ -655,8 +655,7 @@ static void PesParse(PesDemux * pesdx, const uint8_t * data, int size, int is_st
|
||||
// 7/9 bytes 0xFFFxxxxxxxxxxx ADTS audio
|
||||
// PCM audio can't be found
|
||||
// FIXME: simple+faster detection, if codec already known
|
||||
r = 0;
|
||||
if (!r && FastMpegCheck(q)) {
|
||||
if (FastMpegCheck(q)) {
|
||||
r = MpegCheck(q, n);
|
||||
codec_id = AV_CODEC_ID_MP2;
|
||||
}
|
||||
@@ -1327,6 +1326,7 @@ static VideoStream MyVideoStream[1]; ///< normal video stream
|
||||
|
||||
#ifdef USE_PIP
|
||||
static VideoStream PipVideoStream[1]; ///< pip video stream
|
||||
static int PiPActive = 0, mwx, mwy, mww, mwh; ///< main window frame for PiP
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
@@ -1490,7 +1490,7 @@ static void VideoNextPacket(VideoStream * stream, int codec_id)
|
||||
VideoResetPacket(stream);
|
||||
}
|
||||
|
||||
#ifdef USE_PIP
|
||||
#if defined(USE_PIP) || defined(VAAPI)
|
||||
|
||||
/**
|
||||
** Place mpeg video data in packet ringbuffer.
|
||||
@@ -1832,7 +1832,7 @@ int VideoPollInput(VideoStream * stream)
|
||||
** @retval 1 stream paused
|
||||
** @retval -1 empty stream
|
||||
*/
|
||||
int VideoDecodeInput(VideoStream * stream)
|
||||
int VideoDecodeInput(VideoStream * stream, int trick)
|
||||
{
|
||||
int filled;
|
||||
AVPacket *avpkt;
|
||||
@@ -1850,6 +1850,9 @@ int VideoDecodeInput(VideoStream * stream)
|
||||
stream->Close = 0;
|
||||
return 1;
|
||||
}
|
||||
if (stream->ClearBuffers && trick)
|
||||
stream->ClearBuffers = 0;
|
||||
|
||||
if (stream->ClearBuffers) { // clear buffer request
|
||||
atomic_set(&stream->PacketsFilled, 0);
|
||||
stream->PacketRead = stream->PacketWrite;
|
||||
@@ -1940,7 +1943,7 @@ int VideoDecodeInput(VideoStream * stream)
|
||||
avpkt->size = avpkt->stream_index;
|
||||
avpkt->stream_index = 0;
|
||||
|
||||
#ifdef USE_PIP
|
||||
#if defined(USE_PIP) || defined(VAAPI)
|
||||
// fprintf(stderr, "[");
|
||||
// DumpMpeg(avpkt->data, avpkt->size);
|
||||
#ifdef STILL_DEBUG
|
||||
@@ -2302,7 +2305,7 @@ int PlayVideo3(VideoStream * stream, const uint8_t * data, int size)
|
||||
}
|
||||
|
||||
// SKIP PES header, begin of start code
|
||||
#ifdef USE_PIP
|
||||
#if defined(USE_PIP) || defined(VAAPI)
|
||||
VideoMpegEnqueue(stream, pts, dts, check - 2, l + 2);
|
||||
#else
|
||||
VideoEnqueue(stream, pts, dts, check - 2, l + 2);
|
||||
@@ -2315,7 +2318,7 @@ int PlayVideo3(VideoStream * stream, const uint8_t * data, int size)
|
||||
return size;
|
||||
}
|
||||
|
||||
#ifdef USE_PIP
|
||||
#if defined(USE_PIP) || defined(VAAPI)
|
||||
if (stream->CodecID == AV_CODEC_ID_MPEG2VIDEO) {
|
||||
// SKIP PES header
|
||||
VideoMpegEnqueue(stream, pts, dts, data + 9 + n, size - 9 - n);
|
||||
@@ -2676,12 +2679,14 @@ void StillPicture(const uint8_t * data, int size)
|
||||
#ifdef STILL_DEBUG
|
||||
fprintf(stderr, "still-picture\n");
|
||||
#endif
|
||||
|
||||
for (i = 0; i < (MyVideoStream->CodecID == AV_CODEC_ID_HEVC ? 12 : 12); ++i) {
|
||||
const uint8_t *split;
|
||||
int n;
|
||||
|
||||
// FIXME: vdr pes recordings sends mixed audio/video
|
||||
if ((data[3] & 0xF0) == 0xE0) { // PES packet
|
||||
|
||||
split = data;
|
||||
n = size;
|
||||
// split the I-frame into single pes packets
|
||||
@@ -2715,7 +2720,7 @@ void StillPicture(const uint8_t * data, int size)
|
||||
|
||||
VideoNextPacket(MyVideoStream, MyVideoStream->CodecID); // terminate last packet
|
||||
} else { // ES packet
|
||||
if (MyVideoStream->CodecID != AV_CODEC_ID_MPEG2VIDEO) {
|
||||
if (0 && MyVideoStream->CodecID != AV_CODEC_ID_MPEG2VIDEO) {
|
||||
VideoNextPacket(MyVideoStream, AV_CODEC_ID_NONE); // close last stream
|
||||
MyVideoStream->CodecID = AV_CODEC_ID_MPEG2VIDEO;
|
||||
}
|
||||
@@ -2872,11 +2877,11 @@ const char *CommandLineHelp(void)
|
||||
" -p device\taudio device for pass-through (hw:0,1 or /dev/dsp1)\n"
|
||||
" -c channel\taudio mixer channel name (fe. PCM)\n" " -d display\tdisplay of x11 server (fe. :0.0)\n"
|
||||
" -f\t\tstart with fullscreen window (only with window manager)\n"
|
||||
" -g geometry\tx11 window geometry wxh+x+y\n"
|
||||
" -r Refresh\tRefreshrate for DRM (default is 50 Hz)\n"
|
||||
" -C Connector\tConnector for DRM (default is current Connector)\n"
|
||||
" -v device\tvideo driver device (cuvid)\n"
|
||||
" -s\t\tstart in suspended mode\n" " -x\t\tstart x11 server, with -xx try to connect, if this fails\n"
|
||||
" -g geometry\tx11 window geometry wxh+x+y\n" " -r Refresh\tRefreshrate for DRM (default is 50 Hz)\n"
|
||||
" -C Connector\tConnector for DRM (default is current Connector)\n"
|
||||
" -S shader\tShader to use.\n\t\tOnly with placebo. Can be repeated for more shaders\n"
|
||||
" -v device\tvideo driver device (cuvid)\n" " -s\t\tstart in suspended mode\n"
|
||||
" -x\t\tstart x11 server, with -xx try to connect, if this fails\n"
|
||||
" -X args\tX11 server arguments (f.e. -nocursor)\n" " -w workaround\tenable/disable workarounds\n"
|
||||
"\tno-hw-decoder\t\tdisable hw decoder, use software decoder only\n"
|
||||
"\tno-mpeg-hw-decoder\tdisable hw decoder for mpeg only\n"
|
||||
@@ -2908,7 +2913,7 @@ int ProcessArgs(int argc, char *const argv[])
|
||||
#endif
|
||||
|
||||
for (;;) {
|
||||
switch (getopt(argc, argv, "-a:c:C:r:d:fg:p:sv:w:xDX:")) {
|
||||
switch (getopt(argc, argv, "-a:c:C:r:d:fg:p:S:sv:w:xDX:")) {
|
||||
case 'a': // audio device for pcm
|
||||
AudioSetDevice(optarg);
|
||||
continue;
|
||||
@@ -2917,10 +2922,16 @@ int ProcessArgs(int argc, char *const argv[])
|
||||
continue;
|
||||
case 'C': // Connector for DRM
|
||||
VideoSetConnector(optarg);
|
||||
continue;
|
||||
case 'r': // Connector for DRM
|
||||
continue;
|
||||
case 'r': // Connector for DRM
|
||||
VideoSetRefresh(optarg);
|
||||
continue;
|
||||
continue;
|
||||
case 'S': // Shader
|
||||
if (VideoSetShader(optarg) < 0) {
|
||||
fprintf(stderr,_("Too much shaders definded\n"));
|
||||
return 0;
|
||||
}
|
||||
continue;
|
||||
case 'p': // pass-through audio device
|
||||
AudioSetPassthroughDevice(optarg);
|
||||
continue;
|
||||
@@ -3370,15 +3381,21 @@ void Resume(void)
|
||||
** @param[out] dropped dropped frames
|
||||
** @param[out] count number of decoded frames
|
||||
*/
|
||||
void GetStats(int *missed, int *duped, int *dropped, int *counter, float *frametime)
|
||||
void GetStats(int *missed, int *duped, int *dropped, int *counter, float *frametime, int *width, int *height,
|
||||
int *color, int *eotf)
|
||||
{
|
||||
*missed = 0;
|
||||
*duped = 0;
|
||||
*dropped = 0;
|
||||
*counter = 0;
|
||||
*frametime = 0.0f;
|
||||
*width = 0;
|
||||
*height = 0;
|
||||
*color = NULL;
|
||||
*eotf = NULL;
|
||||
if (MyVideoStream->HwDecoder) {
|
||||
VideoGetStats(MyVideoStream->HwDecoder, missed, duped, dropped, counter, frametime);
|
||||
VideoGetStats(MyVideoStream->HwDecoder, missed, duped, dropped, counter, frametime, width, height, color,
|
||||
eotf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3392,6 +3409,12 @@ void GetStats(int *missed, int *duped, int *dropped, int *counter, float *framet
|
||||
*/
|
||||
void ScaleVideo(int x, int y, int width, int height)
|
||||
{
|
||||
#ifdef USE_PIP
|
||||
if (PiPActive && !(x & y & width & height)) {
|
||||
Info("[softhddev]%s: fullscreen with PiP active.\n", __FUNCTION__);
|
||||
x = mwx; y = mwy; width = mww; height = mwh;
|
||||
}
|
||||
#endif
|
||||
if (MyVideoStream->HwDecoder) {
|
||||
VideoSetOutputPosition(MyVideoStream->HwDecoder, x, y, width, height);
|
||||
}
|
||||
@@ -3450,6 +3473,8 @@ void PipStart(int x, int y, int width, int height, int pip_x, int pip_y, int pip
|
||||
VideoStreamOpen(PipVideoStream);
|
||||
}
|
||||
PipSetPosition(x, y, width, height, pip_x, pip_y, pip_width, pip_height);
|
||||
mwx = x; mwy = y; mww = width; mwh = height;
|
||||
PiPActive = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3463,6 +3488,8 @@ void PipStop(void)
|
||||
return;
|
||||
}
|
||||
|
||||
PiPActive = 0;
|
||||
mwx = 0; mwy = 0; mww = 0; mwh = 0;
|
||||
ScaleVideo(0, 0, 0, 0);
|
||||
|
||||
PipVideoStream->Close = 1;
|
||||
|
@@ -96,7 +96,7 @@ extern "C"
|
||||
extern void Resume(void);
|
||||
|
||||
/// Get decoder statistics
|
||||
extern void GetStats(int *, int *, int *, int *, float *);
|
||||
extern void GetStats(int *, int *, int *, int *, float *, int *, int *, int *, int *);
|
||||
/// C plugin scale video
|
||||
extern void ScaleVideo(int, int, int, int);
|
||||
|
||||
|
20
video.h
20
video.h
@@ -44,7 +44,7 @@ extern signed char VideoHardwareDecoder; ///< flag use hardware decoder
|
||||
extern char VideoIgnoreRepeatPict; ///< disable repeat pict warning
|
||||
extern int VideoAudioDelay; ///< audio/video delay
|
||||
extern char ConfigStartX11Server; ///< flag start the x11 server
|
||||
|
||||
extern char MyConfigDir[];
|
||||
//----------------------------------------------------------------------------
|
||||
// Prototypes
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -179,9 +179,6 @@ extern void VideoSetBackground(uint32_t);
|
||||
/// Set audio delay.
|
||||
extern void VideoSetAudioDelay(int);
|
||||
|
||||
/// Set auto-crop parameters.
|
||||
extern void VideoSetAutoCrop(int, int, int);
|
||||
|
||||
/// Clear OSD.
|
||||
extern void VideoOsdClear(void);
|
||||
|
||||
@@ -219,7 +216,7 @@ extern uint8_t *VideoGrab(int *, int *, int *, int);
|
||||
extern uint8_t *VideoGrabService(int *, int *, int *);
|
||||
|
||||
/// Get decoder statistics.
|
||||
extern void VideoGetStats(VideoHwDecoder *, int *, int *, int *, int *, float *);
|
||||
extern void VideoGetStats(VideoHwDecoder *, int *, int *, int *, int *, float *, int *, int *, int *, int *);
|
||||
|
||||
/// Get video stream size
|
||||
extern void VideoGetVideoSize(VideoHwDecoder *, int *, int *, int *, int *);
|
||||
@@ -234,7 +231,7 @@ extern void VideoExit(void); ///< Cleanup and exit video module.
|
||||
extern int VideoPollInput(VideoStream *);
|
||||
|
||||
/// Decode video input buffers.
|
||||
extern int VideoDecodeInput(VideoStream *);
|
||||
extern int VideoDecodeInput(VideoStream *, int);
|
||||
|
||||
/// Get number of input buffers.
|
||||
extern int VideoGetBuffers(const VideoStream *);
|
||||
@@ -245,9 +242,20 @@ extern void SetDPMSatBlackScreen(int);
|
||||
/// Raise the frontend window
|
||||
extern int VideoRaiseWindow(void);
|
||||
|
||||
/// Set Shaders
|
||||
extern int VideoSetShader(char *);
|
||||
|
||||
#ifdef USE_OPENGLOSD
|
||||
extern void ActivateOsd(GLuint, int, int, int, int);
|
||||
#endif
|
||||
|
||||
#ifdef GAMMA
|
||||
extern void Init_Gamma();
|
||||
extern void Exit_Gamma();
|
||||
extern void Set_Gamma(float, int);
|
||||
extern void Get_Gamma();
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
long int gettid()
|
||||
{
|
||||
|
Reference in New Issue
Block a user