28 Commits

Author SHA1 Message Date
jojo61
5875e10479 Honor Softstartflag 2020-04-01 12:45:33 +02:00
jojo61
a6e65d953e Fix issue #42 and changes for faster a/v sync 2020-03-31 13:57:43 +02:00
jojo61
fecb81486d Revert Fix for tvguide 2020-03-29 18:36:54 +02:00
jojo61
f756334187 Fix epggrid scolling with tvguide 2020-03-26 12:36:00 +01:00
jojo61
14ba527a45 Fix issue #40 2020-03-16 16:31:47 +01:00
jojo61
ec09dbfb25 Fix issue #41 2020-03-13 08:19:58 +01:00
jojo61
34b1fccb28 Fis issues #36 #37 #38 2020-03-12 08:05:39 +01:00
jojo61
5586618c6e More fixes 2020-03-09 22:59:27 +01:00
jojo61
4dbf2dcc84 Fixes for Maintainer 2020-03-09 16:15:01 +01:00
jojo61
74a2285af0 Fixed typo 2020-03-06 13:58:56 +01:00
jojo61
b2bff4ebd0 Minor fix for vaapi compile 2020-03-06 13:03:21 +01:00
jojo61
84501d314e Switch to ffnvcodec headers 2020-03-06 12:42:14 +01:00
jojo61
04e1b8732d correct conversion BT709 colors to sRGB 2020-03-06 11:51:20 +01:00
jojo61
3e649a5cea Rework shaders - Better HLG Colors 2020-03-06 09:11:08 +01:00
jojo61
feb7479ff8 Update Readme 2020-03-06 09:02:27 +01:00
jojo61
3590eadbaa Update Readme 2020-03-06 08:59:24 +01:00
jojo61
6c0f80979f Try Fix for tvguide 2020-03-04 16:34:40 +01:00
jojo61
189d8cfa53 Fix issue #34 2020-03-04 15:55:57 +01:00
jojo61
73b355c52d Fixed issue #29 2020-03-02 16:20:34 +01:00
jojo61
3d23288bdc Fixed issue #32 2020-03-02 16:11:33 +01:00
jojo61
b1a642e64a Fixed issue #31 2020-03-02 16:06:27 +01:00
jojo61
1b7bfd2087 More openglosd fixes 2020-02-27 16:24:07 +01:00
jojo61
03e69b5e26 Use FT_ULong instead of uint 2020-02-26 16:52:48 +01:00
jojo61
a5b81f8de1 Set cache to zero for broken vaapi 2020-02-20 16:00:16 +01:00
jojo61
2485929c2b more OSD stuff 2020-02-19 15:54:09 +01:00
jojo61
b9fed82109 OSD fixes 2020-02-18 22:02:53 +01:00
jojo61
49db402de6 Fix in makefile 2020-02-02 13:28:36 +01:00
jojo61
7ce842b989 More info in Menue 2020-02-02 13:26:51 +01:00
14 changed files with 628 additions and 906 deletions

104
Makefile
View File

@@ -16,16 +16,16 @@
# 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
LIBPLACEBO ?= 1
# use YADIF deint - only available with cuvid
#YADIF=1
@@ -35,14 +35,39 @@ LIBPLACEBO ?= 0
CONFIG := #-DDEBUG # remove # to enable debug output
#--------------------- no more config needed past this point--------------------------------
# sanitize selections --------
ifneq "$(MAKECMDGOALS)" "clean"
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
#--------------------------
PLUGIN = softhdcuvid
# support OPENGLOSD always needed
@@ -119,7 +144,33 @@ APIVERSION = $(call PKGCFG,apiversion)
### Parse softhddevice config
### Parse config
ifeq ($(VAAPI),1)
CONFIG += -DVAAPI
#LIBPLACEBO=1
PLUGIN = softhdvaapi
LIBS += -lEGL
endif
ifeq ($(DRM),1)
PLUGIN = softhddrm
CONFIG += -DUSE_DRM -DVAAPI
LIBPLACEBO=0
_CFLAGS += $(shell pkg-config --cflags libdrm)
LIBS += -lgbm -ldrm
LIBS += -lEGL
endif
ifeq ($(CUVID),1)
CONFIG += -DUSE_PIP # PIP support
CONFIG += -DCUVID # enable CUVID decoder
LIBS += -lEGL -lGL
ifeq ($(YADIF),1)
CONFIG += -DYADIF # Yadif only with CUVID
endif
endif
ifeq ($(ALSA),1)
CONFIG += -DUSE_ALSA
@@ -148,37 +199,10 @@ _CFLAGS += $(shell pkg-config --cflags freetype2)
LIBS += $(shell pkg-config --libs freetype2)
endif
ifeq ($(VAAPI),1)
CONFIG += -DVAAPI
#LIBPLACEBO=1
PLUGIN = softhdvaapi
LIBS += -lEGL
endif
ifeq ($(LIBPLACEBO),1)
CONFIG += -DPLACEBO
endif
ifeq ($(DRM),1)
PLUGIN = softhddrm
CONFIG += -DUSE_DRM -DVAAPI
_CFLAGS += $(shell pkg-config --cflags libdrm)
LIBS += -lgbm -ldrm
LIBS += -lEGL
endif
ifeq ($(CUVID),1)
CONFIG += -DUSE_PIP # PIP support
CONFIG += -DCUVID # enable CUVID decoder
LIBS += -lEGL -lGL
ifeq ($(YADIF),1)
CONFIG += -DYADIF # Yadif only with CUVID
endif
endif
ARCHIVE = $(PLUGIN)-$(VERSION)
PACKAGE = vdr-$(ARCHIVE)
@@ -252,18 +276,16 @@ 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

View File

@@ -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,21 @@ 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 +70,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 +96,29 @@ 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.
Setup: environment
------
@@ -356,25 +377,7 @@ 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
SD Streams not working very well on vaapi
Optional:

80
audio.c
View File

@@ -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)
@@ -688,7 +690,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 +1158,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 +1293,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 +1990,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 +2005,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 +2022,9 @@ 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;
@@ -2252,7 +2252,7 @@ void AudioEnqueue(const void *samples, int count)
AudioNormalizer(buffer, count);
}
}
n = RingBufferWrite(AudioRing[AudioRingWrite].RingBuffer, buffer, count);
if (n != (size_t)count) {
Error(_("audio: can't place %d samples in ring buffer\n"), count);
@@ -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;
@@ -2325,7 +2325,7 @@ void AudioVideoReady(int64_t pts)
// Audio.PTS = next written sample time stamp
used = RingBufferUsedBytes(AudioRing[AudioRingWrite].RingBuffer);
audio_pts =
audio_pts =
AudioRing[AudioRingWrite].PTS -
(used * 90 * 1000) / (AudioRing[AudioRingWrite].HwSampleRate * AudioRing[AudioRingWrite].HwChannels *
AudioBytesProSample);
@@ -2337,12 +2337,11 @@ void AudioVideoReady(int64_t pts)
if (!AudioRunning) {
int skip;
// 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 +2352,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 +2362,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 +2371,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 +2406,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");
@@ -2512,7 +2479,7 @@ int64_t AudioGetDelay(void)
pts += ((int64_t) RingBufferUsedBytes(AudioRing[AudioRingRead].RingBuffer)
* 90 * 1000) / (AudioRing[AudioRingRead].HwSampleRate * AudioRing[AudioRingRead].HwChannels *
AudioBytesProSample);
Debug(4, "audio: hw+sw delay %zd %" PRId64 "ms\n", RingBufferUsedBytes(AudioRing[AudioRingRead].RingBuffer),
Debug(4,"audio: hw+sw delay %zd %" PRId64 "ms\n", RingBufferUsedBytes(AudioRing[AudioRingRead].RingBuffer),
pts / 90);
return pts;
@@ -2529,6 +2496,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 +2508,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 +2519,7 @@ int64_t AudioGetClock(void)
return AudioRing[AudioRingRead].PTS + 0 * 90 - delay;
}
}
return INT64_C(0x8000000000000000);
return AV_NOPTS_VALUE;
}
/**

424
codec.c
View File

@@ -75,9 +75,6 @@
#endif
#include <pthread.h>
#ifdef MAIN_H
#include MAIN_H
#endif
#include "iatomic.h"
#include "misc.h"
#include "video.h"
@@ -99,7 +96,6 @@ static pthread_mutex_t CodecLockMutex;
/// Flag prefer fast channel switch
char CodecUsePossibleDefectFrames;
AVBufferRef *hw_device_ctx;
//----------------------------------------------------------------------------
// Video
//----------------------------------------------------------------------------
@@ -498,7 +494,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
@@ -602,6 +598,7 @@ void CodecVideoDecode(VideoDecoder * decoder, const AVPacket * avpkt)
}
// 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) {
@@ -650,7 +647,7 @@ void CodecVideoDecode(VideoDecoder * decoder, const AVPacket * avpkt)
void CodecVideoFlushBuffers(VideoDecoder * decoder)
{
if (decoder->VideoCtx) {
avcodec_flush_buffers(decoder->VideoCtx);
avcodec_flush_buffers(decoder->VideoCtx);
}
}
@@ -682,9 +679,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 +701,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
};
///
@@ -835,27 +819,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,385 +1111,7 @@ 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)
@@ -1760,7 +1346,6 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
if (audio_decoder->Resample) {
uint8_t outbuf[8192 * 2 * 8];
uint8_t *out[1];
out[0] = outbuf;
ret =
swr_convert(audio_decoder->Resample, out, sizeof(outbuf) / (2 * audio_decoder->HwChannels),
@@ -1787,6 +1372,7 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
*/
void CodecAudioFlushBuffers(AudioDecoder * decoder)
{
avcodec_flush_buffers(decoder->AudioCtx);
}

View File

@@ -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

1
hdr.c
View File

@@ -392,6 +392,7 @@ static void set_hdr_metadata(int color,int trc, AVFrameSideData *sd1, AVFrameSid
break;
case AVCOL_TRC_SMPTE2084: // 16
eotf = EOTF_ST2084;
break;
default:
eotf = EOTF_TRADITIONAL_GAMMA_SDR;
break;

View File

@@ -270,7 +270,7 @@ bool cShader::CheckCompileErrors(GLuint object, bool program) {
/****************************************************************************************
* cOglGlyph
****************************************************************************************/
cOglGlyph::cOglGlyph(uint charCode, FT_BitmapGlyph ftGlyph) {
cOglGlyph::cOglGlyph(FT_ULong charCode, FT_BitmapGlyph ftGlyph) {
this->charCode = charCode;
bearingLeft = ftGlyph->left;
bearingTop = ftGlyph->top;
@@ -284,7 +284,7 @@ cOglGlyph::~cOglGlyph(void) {
}
int cOglGlyph::GetKerningCache(uint prevSym) {
int cOglGlyph::GetKerningCache(FT_ULong prevSym) {
for (int i = kerningCache.Size(); --i > 0; ) {
if (kerningCache[i].prevSym == prevSym)
return kerningCache[i].kerning;
@@ -292,7 +292,7 @@ int cOglGlyph::GetKerningCache(uint prevSym) {
return KERNING_UNKNOWN;
}
void cOglGlyph::SetKerningCache(uint prevSym, int kerning) {
void cOglGlyph::SetKerningCache(FT_ULong prevSym, int kerning) {
kerningCache.Append(tKerning(prevSym, kerning));
}
@@ -331,6 +331,7 @@ void cOglGlyph::LoadTexture(FT_BitmapGlyph ftGlyph) {
extern "C" void GlxInitopengl();
extern "C" void GlxDrawopengl();
extern "C" void GlxDestroy();
extern "C" void makejpg(uint8_t *data, int width, int height);
/****************************************************************************************
* cOglFont
****************************************************************************************/
@@ -389,7 +390,7 @@ void cOglFont::Cleanup(void) {
esyslog("failed to deinitialize FreeType library!");
}
cOglGlyph* cOglFont::Glyph(uint charCode) const {
cOglGlyph* cOglFont::Glyph(FT_ULong charCode) const {
// Non-breaking space:
if (charCode == 0xA0)
charCode = 0x20;
@@ -452,7 +453,7 @@ cOglGlyph* cOglFont::Glyph(uint charCode) const {
return Glyph;
}
int cOglFont::Kerning(cOglGlyph *glyph, uint prevSym) const {
int cOglFont::Kerning(cOglGlyph *glyph, FT_ULong prevSym) const {
int kerning = 0;
if (glyph && prevSym) {
kerning = glyph->GetKerningCache(prevSym);
@@ -475,6 +476,7 @@ cOglFb::cOglFb(GLint width, GLint height, GLint viewPortWidth, GLint viewPortHei
initiated = false;
fb = 0;
texture = 0;
this->width = width;
this->height = height;
this->viewPortWidth = viewPortWidth;
@@ -495,8 +497,7 @@ cOglFb::~cOglFb(void) {
bool cOglFb::Init(void) {
initiated = true;
glGenTextures(1, &texture);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -770,6 +771,7 @@ cOglCmdRenderFbToBufferFb::cOglCmdRenderFbToBufferFb(cOglFb *fb, cOglFb *buffer,
this->drawPortX = (GLfloat)drawPortX;
this->drawPortY = (GLfloat)drawPortY;
this->transparency = transparency;
}
bool cOglCmdRenderFbToBufferFb::Execute(void) {
@@ -780,15 +782,15 @@ bool cOglCmdRenderFbToBufferFb::Execute(void) {
GLfloat texY1 = drawPortY / (GLfloat)fb->Height();
GLfloat texX2 = texX1 + 1.0f;
GLfloat texY2 = texY1 + 1.0f;
if (fb->Scrollable()) {
GLfloat pageHeight = (GLfloat)fb->ViewportHeight() / (GLfloat)fb->Height();
texX1 = abs(drawPortX) / (GLfloat)fb->Width();
texY1 = 1.0f - pageHeight - abs(drawPortY) / (GLfloat)fb->Height();
texX2 = texX1 + (GLfloat)fb->ViewportWidth() / (GLfloat)fb->Width();
// x2 = x + fb->Width();
texY2 = texY1 + pageHeight;
}
GLfloat quadVertices[] = {
// Pos // TexCoords
x , y , texX1, texY2, //left top
@@ -805,9 +807,11 @@ bool cOglCmdRenderFbToBufferFb::Execute(void) {
VertexBuffers[vbTexture]->SetShaderProjectionMatrix(buffer->Width(), buffer->Height());
buffer->Bind();
if (!fb->BindTexture())
return false;
VertexBuffers[vbTexture]->Bind();
VertexBuffers[vbTexture]->Bind();
VertexBuffers[vbTexture]->SetVertexData(quadVertices);
VertexBuffers[vbTexture]->DrawArrays();
VertexBuffers[vbTexture]->Unbind();
@@ -826,17 +830,16 @@ cOglCmdCopyBufferToOutputFb::cOglCmdCopyBufferToOutputFb(cOglFb *fb, cOglOutputF
extern unsigned char *posd;
bool cOglCmdCopyBufferToOutputFb::Execute(void) {
int i;
pthread_mutex_lock(&OSDMutex);
fb->BindRead();
oFb->BindWrite();
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
if (posd)
glReadPixels(0, 0 ,fb->Width(), fb->Height(),GL_RGBA,GL_UNSIGNED_BYTE,posd);
glFlush();
oFb->Unbind();
pthread_mutex_unlock(&OSDMutex);
ActivateOsd(oFb->texture,x, y, fb->Width() ,fb->Height());
return true;
@@ -1173,6 +1176,7 @@ cOglCmdDrawText::cOglCmdDrawText( cOglFb *fb, GLint x, GLint y, unsigned int *sy
this->colorText = colorText;
this->fontSize = fontSize;
this->symbols = symbols;
this->fontName = name;
}
cOglCmdDrawText::~cOglCmdDrawText(void) {
@@ -1194,15 +1198,15 @@ bool cOglCmdDrawText::Execute(void) {
int xGlyph = x;
int fontHeight = f->Height();
int bottom = f->Bottom();
uint sym = 0;
uint prevSym = 0;
FT_ULong sym = 0;
FT_ULong prevSym = 0;
int kerning = 0;
for (int i = 0; symbols[i]; i++) {
sym = symbols[i];
cOglGlyph *g = f->Glyph(sym);
if (!g) {
esyslog("[softhddev]ERROR: could not load glyph %x", sym);
esyslog("[softhddev]ERROR: could not load glyph %lx", sym);
}
if ( limitX && xGlyph + g->AdvanceX() > limitX ) {
@@ -1236,7 +1240,6 @@ bool cOglCmdDrawText::Execute(void) {
if ( xGlyph > fb->Width() - 1 )
break;
}
glBindTexture(GL_TEXTURE_2D, 0);
VertexBuffers[vbText]->Unbind();
fb->Unbind();
@@ -1263,6 +1266,7 @@ cOglCmdDrawImage::~cOglCmdDrawImage(void) {
bool cOglCmdDrawImage::Execute(void) {
GLuint texture;
#ifdef USE_DRM
// pthread_mutex_lock(&OSDMutex);
GlxDrawopengl(); // here we need the Shared Context for upload
GlxCheck();
#endif
@@ -1284,9 +1288,11 @@ bool cOglCmdDrawImage::Execute(void) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
glFlush();
#ifdef USE_DRM
GlxInitopengl(); // Reset Context
GlxCheck();
// pthread_mutex_unlock(&OSDMutex);
#endif
GLfloat x1 = x; //left
@@ -1378,6 +1384,7 @@ cOglCmdStoreImage::~cOglCmdStoreImage(void) {
bool cOglCmdStoreImage::Execute(void) {
#ifdef USE_DRM
// pthread_mutex_lock(&OSDMutex);
GlxDrawopengl(); // here we need the Shared Context for upload
GlxCheck();
#endif
@@ -1399,9 +1406,11 @@ bool cOglCmdStoreImage::Execute(void) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
glFlush();
#ifdef USE_DRM
GlxInitopengl(); // Reset Context
GlxCheck();
// pthread_mutex_lock(&OSDMutex);
#endif
return true;
}
@@ -1476,6 +1485,10 @@ void cOglThread::DoCmd(cOglCmd* cmd) {
}
int cOglThread::StoreImage(const cImage &image) {
if (!maxCacheSize) {
return 0;
}
if (image.Width() > maxTextureSize || image.Height() > maxTextureSize) {
esyslog("[softhddev] cannot store image of %dpx x %dpx "
@@ -1815,7 +1828,6 @@ void cOglPixmap::DrawImage(const cPoint &Point, const cImage &Image) {
memcpy(argb, Image.Data(), sizeof(tColor) * Image.Width() * Image.Height());
oglThread->DoCmd(new cOglCmdDrawImage(fb, argb, Image.Width(), Image.Height(), Point.X(), Point.Y()));
SetDirty();
MarkDrawPortDirty(cRect(Point, cSize(Image.Width(), Image.Height())).Intersected(DrawPort().Size()));
}
@@ -1823,6 +1835,7 @@ void cOglPixmap::DrawImage(const cPoint &Point, const cImage &Image) {
void cOglPixmap::DrawImage(const cPoint &Point, int ImageHandle) {
if (!oglThread->Active())
return;
if (ImageHandle < 0 && oglThread->GetImageRef(ImageHandle)) {
sOglImage *img = oglThread->GetImageRef(ImageHandle);
oglThread->DoCmd(new cOglCmdDrawTexture(fb, img, Point.X(), Point.Y()));
@@ -1863,6 +1876,7 @@ void cOglPixmap::DrawBitmap(const cPoint &Point, const cBitmap &Bitmap, tColor C
(index == 0 ? ColorBg : index == 1 ? ColorFg :
Bitmap.Color(index)) : Bitmap.Color(index));
}
oglThread->DoCmd(new cOglCmdDrawImage(fb, argb, Bitmap.Width(), Bitmap.Height(), Point.X(), Point.Y(), Overlay));
SetDirty();
MarkDrawPortDirty(cRect(Point, cSize(Bitmap.Width(), Bitmap.Height())).Intersected(DrawPort().Size()));
@@ -1881,7 +1895,6 @@ void cOglPixmap::DrawText(const cPoint &Point, const char *s, tColor ColorFg, tC
Utf8ToArray(s, symbols, len + 1);
else
symbols[0] = 0;
int x = Point.X();
int y = Point.Y();
int w = Font->Width(s);
@@ -1984,17 +1997,18 @@ cOglOsd::cOglOsd(int Left, int Top, uint Level, std::shared_ptr<cOglThread> oglT
int osdWidth = 0;
int osdHeight = 0;
pthread_mutex_lock(&OSDMutex);
// pthread_mutex_lock(&OSDMutex);
VideoGetOsdSize(&osdWidth, &osdHeight);
// osdWidth = 1920;
// osdHeight = 1080;
dsyslog("[softhddev]cOglOsd osdLeft %d osdTop %d screenWidth %d screenHeight %d", Left, Top, osdWidth, osdHeight);
#if 0
if (posd)
free(posd);
posd = MALLOC(unsigned char, osdWidth * osdHeight * 4);
posd = (unsigned char *)calloc( osdWidth * osdHeight * 4, 1 );
#endif
// create output framebuffer
if (!oFb) {
@@ -2002,17 +2016,13 @@ cOglOsd::cOglOsd(int Left, int Top, uint Level, std::shared_ptr<cOglThread> oglT
oglThread->DoCmd(new cOglCmdInitOutputFb(oFb));
}
pthread_mutex_unlock(&OSDMutex);
// pthread_mutex_unlock(&OSDMutex);
}
cOglOsd::~cOglOsd() {
OsdClose();
SetActive(false);
#if 0
if (posd)
free(posd);
posd = 0;
#endif
oglThread->DoCmd(new cOglCmdDeleteFb(bFb));
}
@@ -2072,6 +2082,7 @@ void cOglOsd::DestroyPixmap(cPixmap *Pixmap) {
return;
if (!Pixmap)
return;
LOCK_PIXMAPS;
int start = 1;
if (isSubtitleOsd)
@@ -2113,7 +2124,7 @@ void cOglOsd::Flush(void) {
oglThread->DoCmd(new cOglCmdRenderFbToBufferFb( oglPixmaps[i]->Fb(),
bFb,
oglPixmaps[i]->ViewPort().X(),
(!isSubtitleOsd) ? oglPixmaps[i]->ViewPort().Y() : 0,
(!isSubtitleOsd) ? oglPixmaps[i]->ViewPort().Y() : 0,
oglPixmaps[i]->Alpha(),
oglPixmaps[i]->DrawPort().X(),
oglPixmaps[i]->DrawPort().Y()));
@@ -2134,3 +2145,4 @@ void cOglOsd::DrawScaledBitmap(int x, int y, const cBitmap &Bitmap, double Facto
int yNew = y - oglPixmaps[0]->ViewPort().Y();
oglPixmaps[0]->DrawBitmap(cPoint(x, yNew), Bitmap);
}

View File

@@ -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;
};
/****************************************************************************************

377
shaders.h
View File

@@ -1,4 +1,5 @@
// shader
#define SHADER_LENGTH 10000
#ifdef CUVID
const char *gl_version = "#version 330";
@@ -10,173 +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.:
@@ -236,6 +70,18 @@ float cms_matrix[3][3] = { {1.660497, -0.124547, -0.018154},
{-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 +118,54 @@ 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 +177,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 +197,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;
}
@@ -332,42 +245,138 @@ static GLuint sc_generate(GLuint gl_prog, enum AVColorSpace colorspace)
GLint cmsLoc;
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;
}
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");
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);
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++) {

View File

@@ -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.1.0"
#ifdef GIT_REV
"-GIT" GIT_REV
#endif
@@ -1133,7 +1133,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;
@@ -2153,6 +2153,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 +2191,30 @@ 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
}
@@ -3435,11 +3459,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 {

View File

@@ -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;
}
@@ -3370,15 +3369,19 @@ 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);
}
}

View File

@@ -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);

300
video.c
View File

@@ -132,11 +132,6 @@ typedef enum
#ifdef USE_GLX
#include <GL/glew.h>
// #include <GL/gl.h> // For GL_COLOR_BUFFER_BIT
// #include <GL/glext.h> // For GL_COLOR_BUFFER_BIT
// #include <GL/glxew.h>
// #include <GL/glx.h>
// only for gluErrorString
#include <GL/glu.h>
#include <GL/glut.h>
#include <GL/freeglut_ext.h>
@@ -146,11 +141,8 @@ typedef enum
#include <libavutil/pixdesc.h>
#ifdef CUVID
// #include <GL/gl.h> // For GL_COLOR_BUFFER_BIT
// #include <GL/glext.h> // For GL_COLOR_BUFFER_BIT
#include <cuda.h>
#include <cuda_runtime_api.h>
#include <cudaGL.h>
#include <ffnvcodec/dynlink_cuda.h>
#include <ffnvcodec/dynlink_loader.h>
#include <libavutil/hwcontext_cuda.h>
#include "drvapi_error_string.h"
#define __DEVICE_TYPES_H__
@@ -297,7 +289,7 @@ typedef struct _video_module_
void (*const ResetStart)(const VideoHwDecoder *);
void (*const SetTrickSpeed)(const VideoHwDecoder *, int);
uint8_t *(*const GrabOutput)(int *, int *, int *, int);
void (*const GetStats)(VideoHwDecoder *, int *, int *, int *, int *, float *);
void (*const GetStats)(VideoHwDecoder *, int *, int *, int *, int *, float *, int *, int *, int *, int *);
void (*const SetBackground)(uint32_t);
void (*const SetVideoMode)(void);
@@ -337,7 +329,7 @@ typedef struct
#define CODEC_SURFACES_MAX 12 //
#define VIDEO_SURFACES_MAX 6 ///< video output surfaces for queue
// #define OUTPUT_SURFACES_MAX 4 ///< output surfaces for flip page
#if defined VAAPI && !defined RASPI
#define PIXEL_FORMAT AV_PIX_FMT_VAAPI
#define SWAP_BUFFER_SIZE 3
@@ -392,7 +384,7 @@ static char VideoSurfaceModesChanged; ///< flag surface modes changed
static const char VideoTransparentOsd = 1;
static uint32_t VideoBackground; ///< video background color
static char VideoStudioLevels; ///< flag use studio levels
char VideoStudioLevels; ///< flag use studio levels
/// Default deinterlace mode.
static VideoDeinterlaceModes VideoDeinterlace[VideoResolutionMax];
@@ -536,7 +528,6 @@ EGLContext OSDcontext;
static GLuint OsdGlTextures[2]; ///< gl texture for OSD
static int OsdIndex = 0; ///< index into OsdGlTextures
//----------------------------------------------------------------------------
// Common Functions
//----------------------------------------------------------------------------
@@ -1423,6 +1414,10 @@ typedef struct _cuvid_decoder_
static CuvidDecoder *CuvidDecoders[2]; ///< open decoder streams
static int CuvidDecoderN; ///< number of decoder streams
#ifdef CUVID
static CudaFunctions *cu;
#endif
#ifdef PLACEBO
typedef struct priv
{
@@ -1514,8 +1509,7 @@ int CuvidMessage(int level, const char *format, ...)
static inline void __checkCudaErrors(CUresult err, const char *file, const int line)
{
if (CUDA_SUCCESS != err) {
CuvidMessage(2, "checkCudaErrors() Driver API error = %04d \"%s\" from file <%s>, line %i.\n", err,
getCudaDrvErrorString(err), file, line);
CuvidMessage(2, "checkCudaErrors() Driver API error = %04d >%s< from file <%s>, line %i.\n", err, getCudaDrvErrorString(err), file, line);
exit(EXIT_FAILURE);
}
}
@@ -1592,7 +1586,7 @@ static void CuvidDestroySurfaces(CuvidDecoder * decoder)
}
#else
#ifdef CUVID
checkCudaErrors(cuGraphicsUnregisterResource(decoder->cu_res[i][j]));
checkCudaErrors(cu->cuGraphicsUnregisterResource(decoder->cu_res[i][j]));
#endif
#ifdef VAAPI
if (decoder->images[i*Planes+j]) {
@@ -1610,7 +1604,7 @@ static void CuvidDestroySurfaces(CuvidDecoder * decoder)
pl_renderer_destroy(&p->renderer);
p->renderer = pl_renderer_create(p->ctx, p->gpu);
#else
glDeleteTextures(CODEC_SURFACES_MAX * 2, (GLuint *) & decoder->gl_textures);
glDeleteTextures(CODEC_SURFACES_MAX * 2, (GLuint *) &decoder->gl_textures);
GlxCheck();
if (CuvidDecoderN == 1) { // only wenn last decoder closes
@@ -2209,7 +2203,7 @@ void generateCUDAImage(CuvidDecoder * decoder, int index, const AVFrame * frame,
.WidthInBytes = image_width * bytes,
.Height = n == 0 ? image_height : image_height / 2,
};
checkCudaErrors(cuMemcpy2D(&cpy));
checkCudaErrors(cu->cuMemcpy2D(&cpy));
}
}
@@ -2294,7 +2288,7 @@ void createTextureDst(CuvidDecoder * decoder, int anz, unsigned int size_x, unsi
.size = decoder->pl_images[i].planes[n].texture->shared_mem.size, // image_width * image_height * bytes,
.flags = 0,
};
checkCudaErrors(cuImportExternalMemory(&decoder->ebuf[i * 2 + n].mem, &ext_desc)); // Import Memory segment
checkCudaErrors(cu->cuImportExternalMemory(&decoder->ebuf[i * 2 + n].mem, &ext_desc)); // Import Memory segment
CUDA_EXTERNAL_MEMORY_MIPMAPPED_ARRAY_DESC tex_desc = {
.offset = decoder->pl_images[i].planes[n].texture->shared_mem.offset,
.arrayDesc = {
@@ -2307,9 +2301,9 @@ void createTextureDst(CuvidDecoder * decoder, int anz, unsigned int size_x, unsi
},
.numLevels = 1,
};
checkCudaErrors(cuExternalMemoryGetMappedMipmappedArray(&decoder->ebuf[i * 2 + n].mma,
checkCudaErrors(cu->cuExternalMemoryGetMappedMipmappedArray(&decoder->ebuf[i * 2 + n].mma,
decoder->ebuf[i * 2 + n].mem, &tex_desc));
checkCudaErrors(cuMipmappedArrayGetLevel(&decoder->cu_array[i][n], decoder->ebuf[i * 2 + n].mma, 0));
checkCudaErrors(cu->cuMipmappedArrayGetLevel(&decoder->cu_array[i][n], decoder->ebuf[i * 2 + n].mma, 0));
#endif
}
// make image
@@ -2421,6 +2415,9 @@ void createTextureDst(CuvidDecoder * decoder, int anz, unsigned int size_x, unsi
glXMakeCurrent(XlibDisplay, VideoWindow, glxSharedContext);
GlxCheck();
#else
#ifdef USE_DRM
pthread_mutex_lock(&OSDMutex);
#endif
eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, eglSharedContext);
#endif
@@ -2454,12 +2451,12 @@ void createTextureDst(CuvidDecoder * decoder, int anz, unsigned int size_x, unsi
SDK_CHECK_ERROR_GL();
// register this texture with CUDA
#ifdef CUVID
checkCudaErrors(cuGraphicsGLRegisterImage(&decoder->cu_res[i][n], decoder->gl_textures[i * Planes + n],
checkCudaErrors(cu->cuGraphicsGLRegisterImage(&decoder->cu_res[i][n], decoder->gl_textures[i * Planes + n],
GL_TEXTURE_2D, CU_GRAPHICS_REGISTER_FLAGS_WRITE_DISCARD));
checkCudaErrors(cuGraphicsMapResources(1, &decoder->cu_res[i][n], 0));
checkCudaErrors(cuGraphicsSubResourceGetMappedArray(&decoder->cu_array[i][n], decoder->cu_res[i][n], 0,
checkCudaErrors(cu->cuGraphicsMapResources(1, &decoder->cu_res[i][n], 0));
checkCudaErrors(cu->cuGraphicsSubResourceGetMappedArray(&decoder->cu_array[i][n], decoder->cu_res[i][n], 0,
0));
checkCudaErrors(cuGraphicsUnmapResources(1, &decoder->cu_res[i][n], 0));
checkCudaErrors(cu->cuGraphicsUnmapResources(1, &decoder->cu_res[i][n], 0));
#endif
}
}
@@ -2467,6 +2464,9 @@ void createTextureDst(CuvidDecoder * decoder, int anz, unsigned int size_x, unsi
GlxCheck();
#ifdef VAAPI
eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
#ifdef USE_DRM
pthread_mutex_unlock(&OSDMutex);
#endif
#endif
}
@@ -2489,9 +2489,8 @@ void createTextureDst(CuvidDecoder * decoder, int anz, unsigned int size_x, unsi
desc.layers[n].pitch[plane]); \
} while (0)
void generateVAAPIImage(CuvidDecoder * decoder, int index, const AVFrame * frame, int image_width, int image_height)
void generateVAAPIImage(CuvidDecoder * decoder, VASurfaceID index, const AVFrame * frame, int image_width, int image_height)
{
int n, i;
VAStatus status;
uint64_t first_time;
@@ -2499,14 +2498,14 @@ void generateVAAPIImage(CuvidDecoder * decoder, int index, const AVFrame * frame
VADRMPRIMESurfaceDescriptor desc;
status =
vaExportSurfaceHandle(decoder->VaDisplay, (unsigned int)frame->data[3], VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
vaExportSurfaceHandle(decoder->VaDisplay, (VASurfaceID)(uintptr_t)frame->data[3], VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
VA_EXPORT_SURFACE_READ_ONLY | VA_EXPORT_SURFACE_SEPARATE_LAYERS, &desc);
if (status != VA_STATUS_SUCCESS) {
printf("Fehler beim export VAAPI Handle\n");
return;
}
vaSyncSurface(decoder->VaDisplay, (unsigned int)frame->data[3]);
vaSyncSurface(decoder->VaDisplay, (VASurfaceID)(uintptr_t)frame->data[3]);
#endif
#ifdef RASPI
AVDRMFrameDescriptor desc;
@@ -2519,7 +2518,7 @@ void generateVAAPIImage(CuvidDecoder * decoder, int index, const AVFrame * frame
for (int n = 0; n < Planes; n++) {
int attribs[20] = { EGL_NONE };
int num_attribs = 0;
uint num_attribs = 0;
int fd;
#if defined (VAAPI) && !defined (RASPI)
ADD_ATTRIB(EGL_LINUX_DRM_FOURCC_EXT, desc.layers[n].drm_format);
@@ -2558,11 +2557,11 @@ void generateVAAPIImage(CuvidDecoder * decoder, int index, const AVFrame * frame
decoder->fds[index*Planes+n] = fd;
#endif
}
decoder->fds[index*Planes+n] = desc.objects[0].fd;
decoder->fds[index*Planes] = desc.objects[0].fd;
glBindTexture(GL_TEXTURE_2D, 0);
eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
EglCheck();
return 0;
return;
esh_failed:
Debug(3, "Failure in generateVAAPIImage\n");
@@ -2609,13 +2608,13 @@ static unsigned CuvidGetVideoSurface(CuvidDecoder * decoder, const AVCodecContex
}
#if defined (VAAPI) || defined (YADIF)
static void CuvidSyncRenderFrame(CuvidDecoder * decoder, const AVCodecContext * video_ctx, const AVFrame * frame);
static void CuvidSyncRenderFrame(CuvidDecoder * decoder, const AVCodecContext * video_ctx, AVFrame * frame);
int push_filters(AVCodecContext * dec_ctx, CuvidDecoder * decoder, AVFrame * frame)
{
int ret, i = 0;
int ret;
AVFrame *filt_frame = av_frame_alloc();
/* push the decoded frame into the filtergraph */
@@ -2868,7 +2867,7 @@ static enum AVPixelFormat Cuvid_get_format(CuvidDecoder * decoder, AVCodecContex
Fatal(_("video: no valid profile found\n"));
}
decoder->newchannel = 1;
// decoder->newchannel = 1;
#ifdef VAAPI
init_generic_hwaccel(decoder, PIXEL_FORMAT,video_ctx);
#endif
@@ -2877,7 +2876,7 @@ static enum AVPixelFormat Cuvid_get_format(CuvidDecoder * decoder, AVCodecContex
}
ist->GetFormatDone = 1;
Debug(3, "video: create decoder 16bit?=%d %dx%d old %d %d\n", bitformat16, video_ctx->width, video_ctx->height,
decoder->InputWidth, decoder->InputHeight);
@@ -2893,13 +2892,14 @@ static enum AVPixelFormat Cuvid_get_format(CuvidDecoder * decoder, AVCodecContex
ist->hwaccel_output_format = AV_PIX_FMT_NV12;
}
// if ((video_ctx->width != decoder->InputWidth
// || video_ctx->height != decoder->InputHeight) && decoder->TrickSpeed == 0) {
if ((video_ctx->width != decoder->InputWidth
|| video_ctx->height != decoder->InputHeight) && decoder->TrickSpeed == 0) {
if (decoder->TrickSpeed == 0) {
// if (decoder->TrickSpeed == 0) {
#ifdef PLACEBO
VideoThreadLock();
#endif
decoder->newchannel = 1;
CuvidCleanup(decoder);
decoder->InputAspect = video_ctx->sample_aspect_ratio;
decoder->InputWidth = video_ctx->width;
@@ -2910,7 +2910,6 @@ static enum AVPixelFormat Cuvid_get_format(CuvidDecoder * decoder, AVCodecContex
#ifdef PLACEBO
VideoThreadUnlock();
// dont show first frame
decoder->newchannel = 1;
#endif
#ifdef YADIF
if (VideoDeinterlace[decoder->Resolution] == VideoDeinterlaceYadif) {
@@ -2925,6 +2924,14 @@ static enum AVPixelFormat Cuvid_get_format(CuvidDecoder * decoder, AVCodecContex
Fatal(_("codec: can't set option deint to video codec!\n"));
}
#endif
} else {
decoder->SyncCounter = 0;
decoder->FrameCounter = 0;
decoder->FramesDisplayed = 0;
decoder->StartCounter = 0;
decoder->Closing = 0;
decoder->PTS = AV_NOPTS_VALUE;
VideoDeltaPTS = 0;
}
CuvidMessage(2, "GetFormat Init ok %dx%d\n", video_ctx->width, video_ctx->height);
@@ -3035,7 +3042,7 @@ int get_RGB(CuvidDecoder * decoder)
if (OsdShown == 1) {
if (OSDtexture)
glDeleteTextures(1, &OSDtexture);
pthread_mutex_lock(&OSDMutex);
// pthread_mutex_lock(&OSDMutex);
glGenTextures(1, &OSDtexture);
glBindTexture(GL_TEXTURE_2D, OSDtexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, OSDxsize, OSDysize, 0, GL_RGBA, GL_UNSIGNED_BYTE, posd);
@@ -3043,7 +3050,7 @@ int get_RGB(CuvidDecoder * decoder)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
pthread_mutex_unlock(&OSDMutex);
// pthread_mutex_unlock(&OSDMutex);
OsdShown = 2;
}
@@ -3087,7 +3094,7 @@ int get_RGB(CuvidDecoder * decoder)
glDeleteFramebuffers(1, &fb);
glDeleteTextures(1, &texture);
#else
#else // Placebo
faktorx = (float)width / (float)VideoWindowWidth;
faktory = (float)height / (float)VideoWindowHeight;
fmt = pl_find_named_fmt(p->gpu, "bgra8");
@@ -3351,9 +3358,11 @@ static void CuvidRenderFrame(CuvidDecoder * decoder, const AVCodecContext * vide
av_frame_free(&frame);
return;
}
if (!decoder->Closing) {
VideoSetPts(&decoder->PTS, decoder->Interlaced, video_ctx, frame);
}
// update aspect ratio changes
if (decoder->InputWidth && decoder->InputHeight && av_cmp_q(decoder->InputAspect, frame->sample_aspect_ratio)) {
Debug(3, "video/cuvid: aspect ratio changed\n");
@@ -3406,11 +3415,6 @@ Debug(3,"fmt %02d:%02d width %d:%d hight %d:%d\n",decoder->ColorSpace,frame->co
av_frame_free(&frame);
return;
}
#if 0
if (!decoder->Closing) {
VideoSetPts(&decoder->PTS, decoder->Interlaced, video_ctx, frame);
}
#endif
#if defined (VAAPI) && defined (PLACEBO)
if (p->has_dma_buf) { // Vulkan supports DMA_BUF no copy required
@@ -3473,7 +3477,7 @@ Debug(3,"fmt %02d:%02d width %d:%d hight %d:%d\n",decoder->ColorSpace,frame->co
///
static void *CuvidGetHwAccelContext(CuvidDecoder * decoder)
{
unsigned int version;
unsigned int version,ret;
Debug(3, "Initializing cuvid hwaccel thread ID:%ld\n", (long int)syscall(186));
// turn NULL;
@@ -3482,16 +3486,23 @@ static void *CuvidGetHwAccelContext(CuvidDecoder * decoder)
Debug(3, "schon passiert\n");
return NULL;
}
if (!cu) {
ret = cuda_load_functions(&cu, NULL);
if (ret < 0) {
Error(_("Could not dynamically load CUDA\n"));
return 0;
}
}
checkCudaErrors(cu->cuInit(0));
checkCudaErrors(cuInit(0));
checkCudaErrors(cuCtxCreate(&decoder->cuda_ctx, (unsigned int)CU_CTX_SCHED_BLOCKING_SYNC, (CUdevice) 0));
checkCudaErrors(cu->cuCtxCreate(&decoder->cuda_ctx, (unsigned int)CU_CTX_SCHED_BLOCKING_SYNC, (CUdevice) 0));
if (decoder->cuda_ctx == NULL)
Fatal(_("Kein Cuda device gefunden"));
cuCtxGetApiVersion(decoder->cuda_ctx, &version);
Debug(3, "***********CUDA API Version %d\n", version);
// cu->cuCtxGetApiVersion(decoder->cuda_ctx, &version);
// Debug(3, "***********CUDA API Version %d\n", version);
#endif
return NULL;
@@ -3614,15 +3625,16 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))
ycropf = (float)decoder->CropY / (float)decoder->InputHeight;
current = decoder->SurfacesRb[decoder->SurfaceRead];
#ifdef USE_DRM
if (!decoder->Closing) {
frame = decoder->frames[current];
VideoSetPts(&decoder->PTS, decoder->Interlaced, 0, frame);
#ifdef USE_DRM
AVFrameSideData *sd1 = av_frame_get_side_data (frame, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA);
AVFrameSideData *sd2 = av_frame_get_side_data (frame, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL);
set_hdr_metadata(frame->color_primaries,frame->color_trc,sd1,sd2);
#endif
}
#endif
// Render Progressive frame
#ifndef PLACEBO
@@ -3666,8 +3678,9 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))
memcpy(&render_params, &pl_render_default_params, sizeof(render_params));
switch (decoder->ColorSpace) {
case AVCOL_SPC_RGB:
case AVCOL_SPC_RGB: // BT 601 is reportet as RGB
img->repr.sys = PL_COLOR_SYSTEM_BT_601;
img->repr.levels = PL_COLOR_LEVELS_TV;
img->color.primaries = PL_COLOR_PRIM_BT_601_625;
img->color.transfer = PL_COLOR_TRC_BT_1886;
img->color.light = PL_COLOR_LIGHT_DISPLAY;
@@ -3676,6 +3689,7 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))
case AVCOL_SPC_BT709:
case AVCOL_SPC_UNSPECIFIED: // comes with UHD
img->repr.sys = PL_COLOR_SYSTEM_BT_709;
img->repr.levels = PL_COLOR_LEVELS_TV;
memcpy(&img->color, &pl_color_space_bt709, sizeof(struct pl_color_space));
// img->color.primaries = PL_COLOR_PRIM_BT_709;
// img->color.transfer = PL_COLOR_TRC_BT_1886;
@@ -3686,6 +3700,7 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))
case AVCOL_SPC_BT2020_NCL:
img->repr.sys = PL_COLOR_SYSTEM_BT_2020_NC;
img->repr.levels = PL_COLOR_LEVELS_TV;
memcpy(&img->repr, &pl_color_repr_uhdtv, sizeof(struct pl_color_repr));
memcpy(&img->color, &pl_color_space_bt2020_hlg, sizeof(struct pl_color_space));
deband.grain = 0.0f; // no grain in HDR
@@ -3701,6 +3716,7 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))
default: // fallback
img->repr.sys = PL_COLOR_SYSTEM_BT_709;
img->repr.levels = PL_COLOR_LEVELS_TV;
memcpy(&img->color, &pl_color_space_bt709, sizeof(struct pl_color_space));
// img->color.primaries = PL_COLOR_PRIM_BT_709;
// img->color.transfer = PL_COLOR_TRC_BT_1886;
@@ -3787,12 +3803,13 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))
colors.contrast = 0.0f;
if (!pl_render_image(p->renderer, &decoder->pl_images[current], target, &render_params)) {
Debug(3, "Failed rendering frame!\n");
}
}
return;
}
decoder->newchannel = 0;
if (!pl_render_image(p->renderer, &decoder->pl_images[current], target, &render_params)) {
Debug(3, "Failed rendering frame!\n");
}
@@ -3831,7 +3848,7 @@ void make_osd_overlay(int x, int y, int width, int height)
{
const struct pl_fmt *fmt;
struct pl_overlay *pl;
const float black[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
int offset = VideoWindowHeight - (VideoWindowHeight - height - y) - (VideoWindowHeight - y);
@@ -3991,6 +4008,7 @@ static void CuvidDisplayFrame(void)
else
target.repr.levels = PL_COLOR_LEVELS_TV;
target.repr.alpha = PL_ALPHA_UNKNOWN;
// target.repr.bits.sample_depth = 16;
// target.repr.bits.color_depth = 16;
// target.repr.bits.bit_shift =0;
@@ -4015,6 +4033,9 @@ static void CuvidDisplayFrame(void)
memcpy(&target.color, &pl_color_space_monitor, sizeof(struct pl_color_space));
break;
}
#ifdef GAMMA
// target.color.transfer = PL_COLOR_TRC_LINEAR;
#endif
#endif
//
// Render videos into output
@@ -4206,7 +4227,7 @@ static int64_t CuvidGetClock(const CuvidDecoder * decoder)
return decoder->PTS - 20 * 90 * (2 * atomic_read(&decoder->SurfacesFilled) - decoder->SurfaceField - 2 + 2);
}
// + 2 in driver queue
return decoder->PTS - 20 * 90 * (atomic_read(&decoder->SurfacesFilled) + SWAP_BUFFER_SIZE - 1); // +2
return decoder->PTS - 20 * 90 * (atomic_read(&decoder->SurfacesFilled) + SWAP_BUFFER_SIZE + 1); // +2
}
///
@@ -4254,13 +4275,17 @@ static void CuvidSetTrickSpeed(CuvidDecoder * decoder, int speed)
/// @param[out] dropped dropped frames
/// @param[out] count number of decoded frames
///
void CuvidGetStats(CuvidDecoder * decoder, int *missed, int *duped, int *dropped, int *counter, float *frametime)
void CuvidGetStats(CuvidDecoder * decoder, int *missed, int *duped, int *dropped, int *counter, float *frametime, int *width, int *height, int *color, int * eotf)
{
*missed = decoder->FramesMissed;
*duped = decoder->FramesDuped;
*dropped = decoder->FramesDropped;
*counter = decoder->FrameCounter;
*frametime = decoder->Frameproc;
*width = decoder->InputWidth;
*height = decoder->InputHeight;
*color = decoder->ColorSpace;
*eotf = 0;
}
///
@@ -4282,10 +4307,15 @@ static void CuvidSyncDecoder(CuvidDecoder * decoder)
int64_t audio_clock;
int64_t video_clock;
int err = 0;
static uint64_t last_time;
static int speedup=3;
// video_clock = CuvidGetClock(decoder);
video_clock = decoder->PTS - (90 * 20 * 1); // 1 Frame in Output
#ifdef GAMMA
Get_Gamma();
#endif
video_clock = CuvidGetClock(decoder);
filled = atomic_read(&decoder->SurfacesFilled);
if (!decoder->SyncOnAudio) {
@@ -4294,7 +4324,7 @@ static void CuvidSyncDecoder(CuvidDecoder * decoder)
goto skip_sync;
}
audio_clock = AudioGetClock();
// printf("Diff %d %ld %ld filled %d \n",(video_clock - audio_clock - VideoAudioDelay)/90,video_clock,audio_clock,filled);
// printf("Diff %d %#012" PRIx64 " %#012" PRIx64" filled %d \n",(video_clock - audio_clock - VideoAudioDelay)/90,video_clock,audio_clock,filled);
// 60Hz: repeat every 5th field
if (Video60HzMode && !(decoder->FramesDisplayed % 6)) {
if (audio_clock == (int64_t) AV_NOPTS_VALUE || video_clock == (int64_t) AV_NOPTS_VALUE) {
@@ -4317,13 +4347,14 @@ static void CuvidSyncDecoder(CuvidDecoder * decoder)
decoder->TrickCounter = decoder->TrickSpeed;
goto skip_sync;
}
#if 0
// at start of new video stream, soft or hard sync video to audio
if (!VideoSoftStartSync && decoder->StartCounter < VideoSoftStartFrames && video_clock != (int64_t) AV_NOPTS_VALUE
&& (audio_clock == (int64_t) AV_NOPTS_VALUE || video_clock > audio_clock + VideoAudioDelay + 120 * 90)) {
Debug(4, "video: initial slow down video, frame %d\n", decoder->StartCounter);
goto out;
goto skip_sync;
}
#endif
if (decoder->SyncCounter && decoder->SyncCounter--) {
goto skip_sync;
}
@@ -4333,44 +4364,49 @@ static void CuvidSyncDecoder(CuvidDecoder * decoder)
int diff;
diff = video_clock - audio_clock - VideoAudioDelay;
diff = (decoder->LastAVDiff + diff) / 2;
// diff = (decoder->LastAVDiff + diff) / 2;
decoder->LastAVDiff = diff;
// if (CuvidDecoderN) {
// CuvidDecoders[0]->Frameproc = (float)(diff / 90);
// }
#if 0
if (abs(diff / 90) > 0) {
printf(" Diff %d filled %d \n", diff / 90, filled);
}
#endif
if (abs(diff) > 5000 * 90) { // more than 5s
err = CuvidMessage(2, "video: audio/video difference too big\n");
err = CuvidMessage(2, "video: audio/video difference too big %d\n",diff/90);
// decoder->SyncCounter = 1;
// usleep(10);
// goto out;
goto skip_sync;
} else if (diff > 100 * 90) {
// FIXME: this quicker sync step, did not work with new code!
err = CuvidMessage(4, "video: slow down video, duping frame %d\n", diff / 90);
++decoder->FramesDuped;
decoder->SyncCounter = 1;
if ((speedup && --speedup) || VideoSoftStartSync)
decoder->SyncCounter = 1;
else
decoder->SyncCounter = 0;
goto out;
} else if (diff > 55 * 90) {
} else if (diff > 25 * 90) {
err = CuvidMessage(3, "video: slow down video, duping frame %d \n", diff / 90);
++decoder->FramesDuped;
decoder->SyncCounter = 1;
goto out;
} else if ((diff < -35 * 90)) {
} else if ((diff < -100 * 90)) {
if (filled > 2) {
err = CuvidMessage(3, "video: speed up video, droping frame %d\n", diff / 90);
++decoder->FramesDropped;
CuvidAdvanceDecoderFrame(decoder);
} else if ((diff < -65 * 90)) { // give it some time to get frames to drop
} else if ((diff < -100 * 90)) { // give it some time to get frames to drop
Debug(3, "Delay Audio %d ms\n", abs(diff / 90));
AudioDelayms(abs(diff / 90));
}
decoder->SyncCounter = 1;
}
else {
speedup = 2;
}
#if defined(DEBUG) || defined(AV_INFO)
if (!decoder->SyncCounter && decoder->StartCounter < 1000) {
#ifdef DEBUG
@@ -4459,7 +4495,7 @@ static void CuvidSyncDisplayFrame(void)
/// @param video_ctx ffmpeg video codec context
/// @param frame frame to display
///
static void CuvidSyncRenderFrame(CuvidDecoder * decoder, const AVCodecContext * video_ctx, const AVFrame * frame)
static void CuvidSyncRenderFrame(CuvidDecoder * decoder, const AVCodecContext * video_ctx, AVFrame * frame)
{
#if 0
// FIXME: temp debug
@@ -4548,15 +4584,12 @@ static void CuvidDisplayHandlerThread(void)
//
filled = atomic_read(&decoder->SurfacesFilled);
//if (filled <= 1 + 2 * decoder->Interlaced) {
if (filled < 4) {
if (filled < 5) {
// FIXME: hot polling
// fetch+decode or reopen
allfull = 0;
err = VideoDecodeInput(decoder->Stream);
} else {
usleep(1000);
err = VideoPollInput(decoder->Stream);
}
// decoder can be invalid here
@@ -4569,25 +4602,17 @@ static void CuvidDisplayHandlerThread(void)
decoder->Closing = -1;
}
}
usleep(1000);
usleep(10 * 1000);
continue;
}
decoded = 1;
}
if (!decoded) { // nothing decoded, sleep
// FIXME: sleep on wakeup
usleep(1 * 1000);
}
usleep(1000);
// all decoder buffers are full
// and display is not preempted
// speed up filling display queue, wait on display queue empty
@@ -4651,7 +4676,7 @@ static const VideoModule CuvidModule = {
.SetTrickSpeed = (void (*const)(const VideoHwDecoder *, int))CuvidSetTrickSpeed,
.GrabOutput = CuvidGrabOutputSurface,
.GetStats = (void (*const)(VideoHwDecoder *, int *, int *, int *,
int *, float *))CuvidGetStats,
int *, float *, int *, int *, int * , int *))CuvidGetStats,
.SetBackground = CuvidSetBackground,
.SetVideoMode = CuvidSetVideoMode,
@@ -4819,7 +4844,7 @@ static const VideoModule NoopModule = {
.SetTrickSpeed =(void (*const)(const VideoHwDecoder *, int))NoopSetTrickSpeed,
.GrabOutput = NoopGrabOutputSurface,
.GetStats = (void (*const)(VideoHwDecoder *, int *, int *, int *,
int *, float *))NoopGetStats,
int *, float *, int *, int *, int * , int *))NoopGetStats,
#endif
.SetBackground = NoopSetBackground,
.SetVideoMode = NoopVoid,
@@ -4971,6 +4996,10 @@ void VideoOsdInit(void)
OsdWidth = VideoWindowWidth;
OsdHeight = VideoWindowHeight;
}
if (posd)
free(posd);
posd = (unsigned char *)calloc( (OsdWidth+1) * (OsdHeight+1) * 4, 1 );
VideoOsdClear();
}
@@ -5182,7 +5211,7 @@ void InitPlacebo()
char xcbext[] = { "VK_KHR_xcb_surface" };
char surfext[] = { "VK_KHR_surface" };
Debug(3, "Init Placebo\n");
Debug(3, "Init Placebo mit API %d\n",PL_API_VER);
p = calloc(1, sizeof(struct priv));
if (!p)
@@ -5278,7 +5307,7 @@ void delete_decode() {
static void *VideoDisplayHandlerThread(void *dummy)
{
prctl(PR_SET_NAME, "video decode", 0, 0, 0);
prctl(PR_SET_NAME, "video decoder", 0, 0, 0);
sleep(2);
pthread_cleanup_push(delete_decode, NULL);
for (;;) {
@@ -5295,6 +5324,11 @@ static void *VideoDisplayHandlerThread(void *dummy)
void exit_display()
{
#ifdef GAMMA
Exit_Gamma();
#endif
#ifdef PLACEBO
Debug(3, "delete placebo\n");
if (p == NULL)
@@ -5343,6 +5377,11 @@ static void *VideoHandlerThread(void *dummy)
prctl(PR_SET_NAME, "video display", 0, 0, 0);
#ifdef GAMMA
Init_Gamma();
Set_Gamma(0.0,6500);
#endif
#ifdef PLACEBO
InitPlacebo();
#else
@@ -5846,9 +5885,9 @@ uint8_t *VideoGrabService(int *size, int *width, int *height)
/// @param[out] dropped dropped frames
/// @param[out] count number of decoded frames
///
void VideoGetStats(VideoHwDecoder * hw_decoder, int *missed, int *duped, int *dropped, int *counter, float *frametime)
void VideoGetStats(VideoHwDecoder * hw_decoder, int *missed, int *duped, int *dropped, int *counter, float *frametime, int *width, int *height, int *color, int *eotf)
{
VideoUsedModule->GetStats(hw_decoder, missed, duped, dropped, counter, frametime);
VideoUsedModule->GetStats(hw_decoder, missed, duped, dropped, counter, frametime, width, height , color, eotf);
}
///
@@ -6594,6 +6633,10 @@ void VideoSetCutLeftRight(int pixels[VideoResolutionMax])
void VideoSetStudioLevels(int onoff)
{
VideoStudioLevels = onoff;
#ifdef GAMMA
Set_Gamma(2.4,6500);
#endif
}
///
@@ -6915,4 +6958,51 @@ void GlxDestroy() {
}
#endif
#if 0 // for debug only
#include <sys/stat.h>
extern uint8_t *CreateJpeg(uint8_t *, int *, int, int, int);
void makejpg(uint8_t *data, int width, int height) {
static int count=0;
int i,n=0,gpu=0;;
char buf[32],FileName[32];
uint8_t *rgb;
uint8_t *jpg_image;
int size,size1;
if (data == NULL) {
data = malloc(width*height*4);
gpu=1;
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, data);
}
// n = snprintf(buf, sizeof(buf), "P6\n%d\n%d\n255\n", width, height);
sprintf(FileName,"/tmp/test%d.jpg",count++);
rgb = malloc(width * height * 3 + n);
if (!rgb) {
printf("Unable to get RGB Memory \n");
return;
}
// memcpy(rgb, buf, n); // header
size = width * height * 4;
for (i = 0; i < size / 4; ++i) { // convert bgra -> rgb
rgb[n + i * 3 + 0] = data[i * 4 + 2];
rgb[n + i * 3 + 1] = data[i * 4 + 1];
rgb[n + i * 3 + 2] = data[i * 4 + 0];
}
if (gpu)
free(data);
jpg_image = CreateJpeg(rgb, &size1, 90, width, height);
int fd = open(FileName, O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC, DEFFILEMODE);
write(fd,jpg_image,size1);
close(fd);
free(rgb);
}
#endif

10
video.h
View File

@@ -219,7 +219,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 *);
@@ -248,6 +248,14 @@ extern int VideoRaiseWindow(void);
#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()
{