mirror of
https://projects.vdr-developer.org/git/vdr-plugin-softhddevice.git
synced 2023-10-10 19:16:51 +02:00
Enable more than 1 vdpau video stream.
This commit is contained in:
parent
d42475f2dc
commit
b54ddd4549
174
video.c
174
video.c
@ -51,6 +51,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define USE_VIDEO_THREAD ///< run decoder in an own thread
|
#define USE_VIDEO_THREAD ///< run decoder in an own thread
|
||||||
|
//#define USE_VIDEO_THREAD2 ///< run decoder+display in own threads
|
||||||
|
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <sys/shm.h>
|
#include <sys/shm.h>
|
||||||
@ -374,6 +375,15 @@ static pthread_mutex_t VideoLockMutex; ///< video lock mutex
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_VIDEO_THREAD2
|
||||||
|
|
||||||
|
static pthread_t VideoDisplayThread; ///< video decode thread
|
||||||
|
static pthread_cond_t VideoWakeupCond; ///< wakeup condition variable
|
||||||
|
static pthread_mutex_t VideoDisplayMutex; ///< video condition mutex
|
||||||
|
static pthread_mutex_t VideoDisplayLockMutex; ///< video lock mutex
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static int OsdConfigWidth; ///< osd configured width
|
static int OsdConfigWidth; ///< osd configured width
|
||||||
static int OsdConfigHeight; ///< osd configured height
|
static int OsdConfigHeight; ///< osd configured height
|
||||||
static char OsdShown; ///< flag show osd
|
static char OsdShown; ///< flag show osd
|
||||||
@ -528,10 +538,12 @@ static void VideoUpdateOutput(AVRational input_aspect_ratio, int input_width,
|
|||||||
normal:
|
normal:
|
||||||
*output_x = video_x;
|
*output_x = video_x;
|
||||||
*output_y = video_y;
|
*output_y = video_y;
|
||||||
*output_width = (video_height * display_aspect_ratio.num)
|
*output_width =
|
||||||
/ display_aspect_ratio.den;
|
(video_height * display_aspect_ratio.num + display_aspect_ratio.den -
|
||||||
*output_height = (video_width * display_aspect_ratio.den)
|
1) / display_aspect_ratio.den;
|
||||||
/ display_aspect_ratio.num;
|
*output_height =
|
||||||
|
(video_width * display_aspect_ratio.den + display_aspect_ratio.num -
|
||||||
|
1) / display_aspect_ratio.num;
|
||||||
if (*output_width > video_width) {
|
if (*output_width > video_width) {
|
||||||
*output_width = video_width;
|
*output_width = video_width;
|
||||||
*output_y += (video_height - *output_height) / 2;
|
*output_y += (video_height - *output_height) / 2;
|
||||||
@ -558,10 +570,12 @@ static void VideoUpdateOutput(AVRational input_aspect_ratio, int input_width,
|
|||||||
*output_height = video_height;
|
*output_height = video_height;
|
||||||
*output_width = video_width;
|
*output_width = video_width;
|
||||||
|
|
||||||
*crop_width = (video_height * display_aspect_ratio.num)
|
*crop_width =
|
||||||
/ display_aspect_ratio.den;
|
(video_height * display_aspect_ratio.num + display_aspect_ratio.den -
|
||||||
*crop_height = (video_width * display_aspect_ratio.den)
|
1) / display_aspect_ratio.den;
|
||||||
/ display_aspect_ratio.num;
|
*crop_height =
|
||||||
|
(video_width * display_aspect_ratio.den + display_aspect_ratio.num -
|
||||||
|
1) / display_aspect_ratio.num;
|
||||||
|
|
||||||
// look which side must be cut
|
// look which side must be cut
|
||||||
if (*crop_width > video_width) {
|
if (*crop_width > video_width) {
|
||||||
@ -571,6 +585,7 @@ static void VideoUpdateOutput(AVRational input_aspect_ratio, int input_width,
|
|||||||
*crop_x = ((*crop_width - video_width) * input_width)
|
*crop_x = ((*crop_width - video_width) * input_width)
|
||||||
/ (2 * video_width);
|
/ (2 * video_width);
|
||||||
*crop_width = input_width - *crop_x * 2;
|
*crop_width = input_width - *crop_x * 2;
|
||||||
|
// FIXME: round failure?
|
||||||
} else if (*crop_height > video_height) {
|
} else if (*crop_height > video_height) {
|
||||||
*crop_width = input_width;
|
*crop_width = input_width;
|
||||||
|
|
||||||
@ -578,6 +593,7 @@ static void VideoUpdateOutput(AVRational input_aspect_ratio, int input_width,
|
|||||||
*crop_y = ((*crop_height - video_height) * input_height)
|
*crop_y = ((*crop_height - video_height) * input_height)
|
||||||
/ (2 * video_height);
|
/ (2 * video_height);
|
||||||
*crop_height = input_height - *crop_y * 2;
|
*crop_height = input_height - *crop_y * 2;
|
||||||
|
// FIXME: round failure?
|
||||||
} else {
|
} else {
|
||||||
*crop_width = input_width;
|
*crop_width = input_width;
|
||||||
*crop_height = input_height;
|
*crop_height = input_height;
|
||||||
@ -4435,10 +4451,10 @@ static void VaapiDisplayFrame(void)
|
|||||||
VaapiDecoder *decoder;
|
VaapiDecoder *decoder;
|
||||||
|
|
||||||
if (VideoSurfaceModesChanged) { // handle changed modes
|
if (VideoSurfaceModesChanged) { // handle changed modes
|
||||||
|
VideoSurfaceModesChanged = 0;
|
||||||
for (i = 0; i < VaapiDecoderN; ++i) {
|
for (i = 0; i < VaapiDecoderN; ++i) {
|
||||||
VaapiInitSurfaceFlags(VaapiDecoders[i]);
|
VaapiInitSurfaceFlags(VaapiDecoders[i]);
|
||||||
}
|
}
|
||||||
VideoSurfaceModesChanged = 0;
|
|
||||||
}
|
}
|
||||||
// look if any stream have a new surface available
|
// look if any stream have a new surface available
|
||||||
for (i = 0; i < VaapiDecoderN; ++i) {
|
for (i = 0; i < VaapiDecoderN; ++i) {
|
||||||
@ -5230,7 +5246,7 @@ typedef struct _vdpau_decoder_
|
|||||||
|
|
||||||
static volatile char VdpauPreemption; ///< flag preemption happened.
|
static volatile char VdpauPreemption; ///< flag preemption happened.
|
||||||
|
|
||||||
static VdpauDecoder *VdpauDecoders[1]; ///< open decoder streams
|
static VdpauDecoder *VdpauDecoders[2]; ///< open decoder streams
|
||||||
static int VdpauDecoderN; ///< number of decoder streams
|
static int VdpauDecoderN; ///< number of decoder streams
|
||||||
|
|
||||||
static VdpDevice VdpauDevice; ///< VDPAU device
|
static VdpDevice VdpauDevice; ///< VDPAU device
|
||||||
@ -5254,6 +5270,7 @@ static VdpChromaType VdpauChromaType; ///< best video surface chroma format
|
|||||||
/// display surface ring buffer
|
/// display surface ring buffer
|
||||||
static VdpOutputSurface VdpauSurfacesRb[OUTPUT_SURFACES_MAX];
|
static VdpOutputSurface VdpauSurfacesRb[OUTPUT_SURFACES_MAX];
|
||||||
static int VdpauSurfaceIndex; ///< current display surface
|
static int VdpauSurfaceIndex; ///< current display surface
|
||||||
|
static struct timespec VdpauFrameTime; ///< time of last display
|
||||||
|
|
||||||
#ifdef USE_BITMAP
|
#ifdef USE_BITMAP
|
||||||
/// bitmap surfaces for osd
|
/// bitmap surfaces for osd
|
||||||
@ -5840,7 +5857,8 @@ static VdpauDecoder *VdpauNewHwDecoder(VideoStream * stream)
|
|||||||
VdpauDecoder *decoder;
|
VdpauDecoder *decoder;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (VdpauDecoderN == 1) {
|
if ((unsigned)VdpauDecoderN >=
|
||||||
|
sizeof(VdpauDecoders) / sizeof(*VdpauDecoders)) {
|
||||||
Error(_("video/vdpau: out of decoders\n"));
|
Error(_("video/vdpau: out of decoders\n"));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -5896,9 +5914,7 @@ static VdpauDecoder *VdpauNewHwDecoder(VideoStream * stream)
|
|||||||
|
|
||||||
decoder->PTS = AV_NOPTS_VALUE;
|
decoder->PTS = AV_NOPTS_VALUE;
|
||||||
|
|
||||||
// FIXME: hack
|
VdpauDecoders[VdpauDecoderN++] = decoder;
|
||||||
VdpauDecoderN = 1;
|
|
||||||
VdpauDecoders[0] = decoder;
|
|
||||||
|
|
||||||
return decoder;
|
return decoder;
|
||||||
}
|
}
|
||||||
@ -7645,10 +7661,10 @@ static void VdpauMixVideo(VdpauDecoder * decoder)
|
|||||||
VdpauCheckAutoCrop(decoder);
|
VdpauCheckAutoCrop(decoder);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
dst_rect.x0 = 0; // window output (clip)
|
dst_rect.x0 = decoder->VideoX; // window output (clip)
|
||||||
dst_rect.y0 = 0;
|
dst_rect.y0 = decoder->VideoY;
|
||||||
dst_rect.x1 = VideoWindowWidth;
|
dst_rect.x1 = decoder->VideoX + decoder->VideoWidth;
|
||||||
dst_rect.y1 = VideoWindowHeight;
|
dst_rect.y1 = decoder->VideoY + decoder->VideoHeight;
|
||||||
|
|
||||||
video_src_rect.x0 = decoder->CropX; // video source (crop)
|
video_src_rect.x0 = decoder->CropX; // video source (crop)
|
||||||
video_src_rect.y0 = decoder->CropY;
|
video_src_rect.y0 = decoder->CropY;
|
||||||
@ -7936,10 +7952,11 @@ static void VdpauDisplayFrame(void)
|
|||||||
Error(_("video/vdpau: can't queue display: %s\n"),
|
Error(_("video/vdpau: can't queue display: %s\n"),
|
||||||
VdpauGetErrorString(status));
|
VdpauGetErrorString(status));
|
||||||
}
|
}
|
||||||
|
// FIXME: CLOCK_MONOTONIC_RAW
|
||||||
|
clock_gettime(CLOCK_REALTIME, &VdpauFrameTime);
|
||||||
for (i = 0; i < VdpauDecoderN; ++i) {
|
for (i = 0; i < VdpauDecoderN; ++i) {
|
||||||
// remember time of last shown surface
|
// remember time of last shown surface
|
||||||
clock_gettime(CLOCK_REALTIME, &VdpauDecoders[i]->FrameTime);
|
VdpauDecoders[i]->FrameTime = VdpauFrameTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
VdpauSurfaceIndex = (VdpauSurfaceIndex + 1) % OUTPUT_SURFACES_MAX;
|
VdpauSurfaceIndex = (VdpauSurfaceIndex + 1) % OUTPUT_SURFACES_MAX;
|
||||||
@ -8311,6 +8328,10 @@ static void VdpauSetVideoMode(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_VIDEO_THREAD2
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
#ifdef USE_VIDEO_THREAD
|
#ifdef USE_VIDEO_THREAD
|
||||||
|
|
||||||
///
|
///
|
||||||
@ -8320,53 +8341,61 @@ static void VdpauSetVideoMode(void)
|
|||||||
///
|
///
|
||||||
static void VdpauDisplayHandlerThread(void)
|
static void VdpauDisplayHandlerThread(void)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
int err;
|
int err;
|
||||||
int filled;
|
int decoded;
|
||||||
struct timespec nowtime;
|
struct timespec nowtime;
|
||||||
VdpauDecoder *decoder;
|
VdpauDecoder *decoder;
|
||||||
|
|
||||||
if (!(decoder = VdpauDecoders[0])) { // no stream available
|
|
||||||
usleep(15 * 1000);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (VdpauPreemption) { // display preempted
|
if (VdpauPreemption) { // display preempted
|
||||||
if (VdpauPreemptionRecover()) {
|
if (VdpauPreemptionRecover()) {
|
||||||
usleep(15 * 1000);
|
usleep(15 * 1000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// fill frame output ring buffer
|
decoded = 0;
|
||||||
//
|
for (i = 0; i < VdpauDecoderN; ++i) {
|
||||||
filled = atomic_read(&decoder->SurfacesFilled);
|
int filled;
|
||||||
if (filled < VIDEO_SURFACES_MAX) {
|
|
||||||
// FIXME: hot polling
|
decoder = VdpauDecoders[i];
|
||||||
pthread_mutex_lock(&VideoLockMutex);
|
|
||||||
// fetch+decode or reopen
|
//
|
||||||
err = VideoDecodeInput(decoder->Stream);
|
// fill frame output ring buffer
|
||||||
pthread_mutex_unlock(&VideoLockMutex);
|
//
|
||||||
} else {
|
filled = atomic_read(&decoder->SurfacesFilled);
|
||||||
err = VideoPollInput(decoder->Stream);
|
if (filled < VIDEO_SURFACES_MAX) {
|
||||||
}
|
// FIXME: hot polling
|
||||||
if (err) {
|
pthread_mutex_lock(&VideoLockMutex);
|
||||||
// FIXME: sleep on wakeup
|
// fetch+decode or reopen
|
||||||
usleep(5 * 1000); // nothing buffered
|
err = VideoDecodeInput(decoder->Stream);
|
||||||
if (err == -1 && decoder->Closing) {
|
pthread_mutex_unlock(&VideoLockMutex);
|
||||||
decoder->Closing--;
|
} else {
|
||||||
if (!decoder->Closing) {
|
err = VideoPollInput(decoder->Stream);
|
||||||
Debug(3, "video/vdpau: closing eof\n");
|
|
||||||
decoder->Closing = -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (err) {
|
||||||
|
// nothing buffered?
|
||||||
|
if (err == -1 && decoder->Closing) {
|
||||||
|
decoder->Closing--;
|
||||||
|
if (!decoder->Closing) {
|
||||||
|
Debug(3, "video/vdpau: closing eof\n");
|
||||||
|
decoder->Closing = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
decoded = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!decoded) { // nothing decoded, sleep
|
||||||
|
// FIXME: sleep on wakeup
|
||||||
|
usleep(5 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
clock_gettime(CLOCK_REALTIME, &nowtime);
|
clock_gettime(CLOCK_REALTIME, &nowtime);
|
||||||
// time for one frame over?
|
// time for one frame over?
|
||||||
if ( //filled<VIDEO_SURFACES_MAX &&
|
if ((nowtime.tv_sec - VdpauFrameTime.tv_sec) * 1000 * 1000 * 1000 +
|
||||||
(nowtime.tv_sec - decoder->FrameTime.tv_sec)
|
(nowtime.tv_nsec - VdpauFrameTime.tv_nsec) < 15 * 1000 * 1000) {
|
||||||
* 1000 * 1000 * 1000 + (nowtime.tv_nsec - decoder->FrameTime.tv_nsec) <
|
|
||||||
15 * 1000 * 1000) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8381,6 +8410,8 @@ static void VdpauDisplayHandlerThread(void)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Set video output position.
|
/// Set video output position.
|
||||||
///
|
///
|
||||||
@ -8395,6 +8426,8 @@ static void VdpauDisplayHandlerThread(void)
|
|||||||
static void VdpauSetOutputPosition(VdpauDecoder * decoder, int x, int y,
|
static void VdpauSetOutputPosition(VdpauDecoder * decoder, int x, int y,
|
||||||
int width, int height)
|
int width, int height)
|
||||||
{
|
{
|
||||||
|
Debug(3, "video/vdapu: output %dx%d%+d%+d\n", width, height, x, y);
|
||||||
|
|
||||||
decoder->VideoX = x;
|
decoder->VideoX = x;
|
||||||
decoder->VideoY = y;
|
decoder->VideoY = y;
|
||||||
decoder->VideoWidth = width;
|
decoder->VideoWidth = width;
|
||||||
@ -10259,17 +10292,11 @@ void VideoSetHue(int hue)
|
|||||||
void VideoSetOutputPosition(VideoHwDecoder * hw_decoder, int x, int y,
|
void VideoSetOutputPosition(VideoHwDecoder * hw_decoder, int x, int y,
|
||||||
int width, int height)
|
int width, int height)
|
||||||
{
|
{
|
||||||
static int last_x; ///< last video output window x
|
|
||||||
static int last_y; ///< last video output window y
|
|
||||||
static unsigned last_width; ///< last video output window width
|
|
||||||
static unsigned last_height; ///< last video output window height
|
|
||||||
|
|
||||||
if (!OsdWidth || !OsdHeight) {
|
if (!OsdWidth || !OsdHeight) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!width || !height) {
|
if (!width || !height) {
|
||||||
// restore full size & remember values to be able to avoid
|
// restore full size
|
||||||
// interfering with the video thread if possible
|
|
||||||
width = VideoWindowWidth;
|
width = VideoWindowWidth;
|
||||||
height = VideoWindowHeight;
|
height = VideoWindowHeight;
|
||||||
} else {
|
} else {
|
||||||
@ -10280,33 +10307,28 @@ void VideoSetOutputPosition(VideoHwDecoder * hw_decoder, int x, int y,
|
|||||||
height = (height * VideoWindowHeight) / OsdHeight;
|
height = (height * VideoWindowHeight) / OsdHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x == last_x && y == last_y && (unsigned)width == last_width
|
|
||||||
&& (unsigned)height == last_height) {
|
|
||||||
// not necessary...
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// scale & remember values to be able to avoid
|
|
||||||
// interfering with the video thread if possible
|
|
||||||
last_x = x;
|
|
||||||
last_y = y;
|
|
||||||
last_width = width;
|
|
||||||
last_height = height;
|
|
||||||
|
|
||||||
VideoThreadLock();
|
|
||||||
// FIXME: what stream?
|
|
||||||
// FIXME: add function to module class
|
// FIXME: add function to module class
|
||||||
#ifdef USE_VDPAU
|
#ifdef USE_VDPAU
|
||||||
if (VideoUsedModule == &VdpauModule) {
|
if (VideoUsedModule == &VdpauModule) {
|
||||||
VdpauSetOutputPosition(&hw_decoder->Vdpau, last_x, last_y, last_width,
|
// check values to be able to avoid
|
||||||
last_height);
|
// interfering with the video thread if possible
|
||||||
|
|
||||||
|
if (x == hw_decoder->Vdpau.VideoX && y == hw_decoder->Vdpau.VideoY
|
||||||
|
&& width == hw_decoder->Vdpau.VideoWidth
|
||||||
|
&& height == hw_decoder->Vdpau.VideoHeight) {
|
||||||
|
// not necessary...
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
VideoThreadLock();
|
||||||
|
VdpauSetOutputPosition(&hw_decoder->Vdpau, x, y, width, height);
|
||||||
VdpauUpdateOutput(&hw_decoder->Vdpau);
|
VdpauUpdateOutput(&hw_decoder->Vdpau);
|
||||||
|
VideoThreadUnlock();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_VAAPI
|
#ifdef USE_VAAPI
|
||||||
// FIXME: not supported by vaapi without unscaled OSD,
|
// FIXME: not supported by vaapi without unscaled OSD,
|
||||||
// FIXME: if used to position video inside osd
|
// FIXME: if used to position video inside osd
|
||||||
#endif
|
#endif
|
||||||
VideoThreadUnlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
Loading…
Reference in New Issue
Block a user