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