Enable more than 1 vdpau video stream.

This commit is contained in:
Johns 2013-01-04 15:54:32 +01:00
parent d42475f2dc
commit b54ddd4549
1 changed files with 98 additions and 76 deletions

174
video.c
View File

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