mirror of
https://github.com/jojo61/vdr-plugin-softhdcuvid.git
synced 2025-03-01 10:39:28 +00:00
Compare commits
28 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
5875e10479 | ||
|
a6e65d953e | ||
|
fecb81486d | ||
|
f756334187 | ||
|
14ba527a45 | ||
|
ec09dbfb25 | ||
|
34b1fccb28 | ||
|
5586618c6e | ||
|
4dbf2dcc84 | ||
|
74a2285af0 | ||
|
b2bff4ebd0 | ||
|
84501d314e | ||
|
04e1b8732d | ||
|
3e649a5cea | ||
|
feb7479ff8 | ||
|
3590eadbaa | ||
|
6c0f80979f | ||
|
189d8cfa53 | ||
|
73b355c52d | ||
|
3d23288bdc | ||
|
b1a642e64a | ||
|
1b7bfd2087 | ||
|
03e69b5e26 | ||
|
a5b81f8de1 | ||
|
2485929c2b | ||
|
b9fed82109 | ||
|
49db402de6 | ||
|
7ce842b989 |
104
Makefile
104
Makefile
@@ -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
|
||||
|
91
README.md
91
README.md
@@ -23,8 +23,8 @@ $Id: 5267da021a68b4a727b479417334bfbe67bbba14 $
|
||||
|
||||
A software and GPU emulated UHD output device plugin for VDR.
|
||||
|
||||
o Video decoder CPU / VDPAU
|
||||
o Video output opengl
|
||||
o Video decoder CUVID or VAAPI
|
||||
o Video output opengl or DRM
|
||||
o Audio FFMpeg / Alsa / Analog
|
||||
o Audio FFMpeg / Alsa / Digital
|
||||
o Audio FFMpeg / OSS / Analog
|
||||
@@ -32,9 +32,10 @@ A software and GPU emulated UHD output device plugin for VDR.
|
||||
o Software volume, compression, normalize and channel resample
|
||||
o VDR ScaleVideo API
|
||||
o CUDA deinterlacer
|
||||
o Autocrop
|
||||
o Suspend / Dettach
|
||||
o PIP (Picture-in-Picture) (not working yet)
|
||||
o Support for ambilight
|
||||
o Support for Screencopy
|
||||
o PIP (Picture-in-Picture) (only for CUVID)
|
||||
|
||||
|
||||
To compile you must have the 'requires' installed.
|
||||
@@ -47,34 +48,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
80
audio.c
@@ -86,6 +86,8 @@
|
||||
#define __USE_GNU
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/resource.h>
|
||||
#ifndef HAVE_PTHREAD_NAME
|
||||
/// only available with newer glibc
|
||||
#define pthread_setname_np(thread, name)
|
||||
@@ -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
424
codec.c
@@ -75,9 +75,6 @@
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
|
||||
#ifdef MAIN_H
|
||||
#include MAIN_H
|
||||
#endif
|
||||
#include "iatomic.h"
|
||||
#include "misc.h"
|
||||
#include "video.h"
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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
1
hdr.c
@@ -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;
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
18
openglosd.h
18
openglosd.h
@@ -103,14 +103,14 @@ class cOglGlyph:public cListObject
|
||||
struct tKerning
|
||||
{
|
||||
public:
|
||||
tKerning(uint prevSym, GLfloat kerning = 0.0f) {
|
||||
tKerning(FT_ULong prevSym, GLfloat kerning = 0.0f) {
|
||||
this->prevSym = prevSym;
|
||||
this->kerning = kerning;
|
||||
}
|
||||
uint prevSym;
|
||||
FT_ULong prevSym;
|
||||
GLfloat kerning;
|
||||
};
|
||||
uint charCode;
|
||||
FT_ULong charCode;
|
||||
int bearingLeft;
|
||||
int bearingTop;
|
||||
int width;
|
||||
@@ -122,9 +122,9 @@ class cOglGlyph:public cListObject
|
||||
void LoadTexture(FT_BitmapGlyph ftGlyph);
|
||||
|
||||
public:
|
||||
cOglGlyph(uint charCode, FT_BitmapGlyph ftGlyph);
|
||||
cOglGlyph(FT_ULong charCode, FT_BitmapGlyph ftGlyph);
|
||||
virtual ~ cOglGlyph();
|
||||
uint CharCode(void)
|
||||
FT_ULong CharCode(void)
|
||||
{
|
||||
return charCode;
|
||||
}
|
||||
@@ -148,8 +148,8 @@ class cOglGlyph:public cListObject
|
||||
{
|
||||
return height;
|
||||
}
|
||||
int GetKerningCache(uint prevSym);
|
||||
void SetKerningCache(uint prevSym, int kerning);
|
||||
int GetKerningCache(FT_ULong prevSym);
|
||||
void SetKerningCache(FT_ULong prevSym, int kerning);
|
||||
void BindTexture(void);
|
||||
};
|
||||
|
||||
@@ -190,8 +190,8 @@ class cOglFont:public cListObject
|
||||
{
|
||||
return height;
|
||||
};
|
||||
cOglGlyph *Glyph(uint charCode) const;
|
||||
int Kerning(cOglGlyph * glyph, uint prevSym) const;
|
||||
cOglGlyph *Glyph(FT_ULong charCode) const;
|
||||
int Kerning(cOglGlyph * glyph, FT_ULong prevSym) const;
|
||||
};
|
||||
|
||||
/****************************************************************************************
|
||||
|
377
shaders.h
377
shaders.h
@@ -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++) {
|
||||
|
@@ -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 {
|
||||
|
13
softhddev.c
13
softhddev.c
@@ -645,7 +645,7 @@ static void PesParse(PesDemux * pesdx, const uint8_t * data, int size, int is_st
|
||||
q = pesdx->Buffer + pesdx->Skip;
|
||||
n = pesdx->Index - pesdx->Skip;
|
||||
while (n >= 5) {
|
||||
int r;
|
||||
int r=0;
|
||||
unsigned codec_id = AV_CODEC_ID_NONE;
|
||||
|
||||
// 4 bytes 0xFFExxxxx Mpeg audio
|
||||
@@ -655,8 +655,7 @@ static void PesParse(PesDemux * pesdx, const uint8_t * data, int size, int is_st
|
||||
// 7/9 bytes 0xFFFxxxxxxxxxxx ADTS audio
|
||||
// PCM audio can't be found
|
||||
// FIXME: simple+faster detection, if codec already known
|
||||
r = 0;
|
||||
if (!r && FastMpegCheck(q)) {
|
||||
if (FastMpegCheck(q)) {
|
||||
r = MpegCheck(q, n);
|
||||
codec_id = AV_CODEC_ID_MP2;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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
300
video.c
@@ -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
10
video.h
@@ -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()
|
||||
{
|
||||
|
Reference in New Issue
Block a user