From 7e5c6f349dc6c59cf113449494eb3e65a8605f1e Mon Sep 17 00:00:00 2001 From: jojo61 Date: Fri, 5 Apr 2019 07:20:52 +0200 Subject: [PATCH] YADIF Deinterlacer --- Makefile | 1 + codec.c | 70 ++++++-- codec.h | 4 +- misc.h | 2 +- softhdcuvid.cpp | 118 ++++++------- softhddev.c | 4 +- video.c | 450 ++++++++++++++++++++++++++++++++++++------------ 7 files changed, 463 insertions(+), 186 deletions(-) diff --git a/Makefile b/Makefile index 66ab4e4..64dd5cb 100644 --- a/Makefile +++ b/Makefile @@ -36,6 +36,7 @@ endif CONFIG := #-DDEBUG #-DOSD_DEBUG # enable debug output+functions CONFIG += -DCUVID # enable CUVID decoder +#CONFIG += -DYADIF # enable yadif_cuda deinterlacer CONFIG += -DHAVE_GL # needed for mpv libs #CONFIG += -DSTILL_DEBUG=2 # still picture debug verbose level diff --git a/codec.c b/codec.c index 681d9d2..e414153 100644 --- a/codec.c +++ b/codec.c @@ -61,6 +61,7 @@ #include #include #include + // support old ffmpeg versions <1.0 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,18,102) #define AVCodecID CodecID @@ -168,18 +169,18 @@ static enum AVPixelFormat Codec_get_format(AVCodecContext * video_ctx, // this begins to stink, 1.1.2 calls get_format for each frame // 1.1.3 has the same version, but works again if (decoder->GetFormatDone) { - if (decoder->GetFormatDone < 10) { - ++decoder->GetFormatDone; - Error - ("codec/video: ffmpeg/libav buggy: get_format called again\n"); - } - return *fmt; // FIXME: this is hack + if (decoder->GetFormatDone < 10) { + ++decoder->GetFormatDone; + Error + ("codec/video: ffmpeg/libav buggy: get_format called again\n"); + } + return *fmt; // FIXME: this is hack } #endif // bug in ffmpeg 1.1.1, called with zero width or height if (!video_ctx->width || !video_ctx->height) { - Error("codec/video: ffmpeg/libav buggy: width or height zero\n"); + Error("codec/video: ffmpeg/libav buggy: width or height zero\n"); } decoder->GetFormatDone = 1; @@ -207,13 +208,13 @@ static int Codec_get_buffer2(AVCodecContext * video_ctx, AVFrame * frame, int fl // libav 0.8.5 53.35.0 still needs this #endif if (!decoder->GetFormatDone) { // get_format missing - enum AVPixelFormat fmts[2]; + enum AVPixelFormat fmts[2]; - fprintf(stderr, "codec: buggy libav, use ffmpeg\n"); - Warning(_("codec: buggy libav, use ffmpeg\n")); - fmts[0] = video_ctx->pix_fmt; - fmts[1] = AV_PIX_FMT_NONE; - Codec_get_format(video_ctx, fmts); + fprintf(stderr, "codec: buggy libav, use ffmpeg\n"); + Warning(_("codec: buggy libav, use ffmpeg\n")); + fmts[0] = video_ctx->pix_fmt; + fmts[1] = AV_PIX_FMT_NONE; + Codec_get_format(video_ctx, fmts); } if (decoder->hwaccel_get_buffer && (AV_PIX_FMT_VDPAU == decoder->hwaccel_pix_fmt || AV_PIX_FMT_CUDA == decoder->hwaccel_pix_fmt)) { //Debug(3,"hwaccel get_buffer\n"); @@ -267,7 +268,7 @@ void CodecVideoOpen(VideoDecoder * decoder, int codec_id) { AVCodec *video_codec; const char *name; - int ret; + int ret,deint=2; Debug(3, "***************codec: Video Open using video codec ID %#06x (%s)\n", codec_id, avcodec_get_name(codec_id)); @@ -321,9 +322,12 @@ void CodecVideoOpen(VideoDecoder * decoder, int codec_id) pthread_mutex_lock(&CodecLockMutex); // open codec +#ifdef YADIF + deint = 0; +#endif if (strcmp(decoder->VideoCodec->long_name,"Nvidia CUVID MPEG2VIDEO decoder") == 0) { // deinterlace for mpeg2 is somehow broken - if (av_opt_set_int(decoder->VideoCtx->priv_data, "deint", 2 ,0) < 0) { // adaptive + if (av_opt_set_int(decoder->VideoCtx->priv_data, "deint", deint ,0) < 0) { // adaptive pthread_mutex_unlock(&CodecLockMutex); Fatal(_("codec: can't set option deint to video codec!\n")); } @@ -339,10 +343,16 @@ void CodecVideoOpen(VideoDecoder * decoder, int codec_id) } } else if (strstr(decoder->VideoCodec->long_name,"Nvidia CUVID") != NULL) { - if (av_opt_set_int(decoder->VideoCtx->priv_data, "deint", 2 ,0) < 0) { // adaptive + if (av_opt_set_int(decoder->VideoCtx->priv_data, "deint", deint ,0) < 0) { // adaptive pthread_mutex_unlock(&CodecLockMutex); Fatal(_("codec: can't set option deint to video codec!\n")); } +#if 1 + if (av_opt_set_int(decoder->VideoCtx->priv_data, "surfaces", 13 ,0) < 0) { + pthread_mutex_unlock(&CodecLockMutex); + Fatal(_("codec: can't set option surfces to video codec!\n")); + } +#endif if (av_opt_set(decoder->VideoCtx->priv_data, "drop_second_field", "false" ,0) < 0) { pthread_mutex_unlock(&CodecLockMutex); Fatal(_("codec: can't set option drop 2.field to video codec!\n")); @@ -383,6 +393,9 @@ void CodecVideoOpen(VideoDecoder * decoder, int codec_id) // reset buggy ffmpeg/libav flag decoder->GetFormatDone = 0; +#ifdef YADIF + decoder->filter = 0; +#endif #ifdef FFMPEG_WORKAROUND_ARTIFACTS decoder->FirstKeyFrame = 1; #endif @@ -458,7 +471,10 @@ void DisplayPts(AVCodecContext * video_ctx, AVFrame * frame) ** @param avpkt video packet */ extern int CuvidTestSurfaces(); - +#ifdef YADIF +extern int init_filters(AVCodecContext * dec_ctx,void * decoder,AVFrame *frame); +extern int push_filters(AVCodecContext * dec_ctx,void * decoder,AVFrame *frame); +#endif void CodecVideoDecode(VideoDecoder * decoder, const AVPacket * avpkt) { AVCodecContext *video_ctx; @@ -467,7 +483,7 @@ void CodecVideoDecode(VideoDecoder * decoder, const AVPacket * avpkt) int got_frame; int consumed = 0; const AVPacket *pkt; - + next_part: video_ctx = decoder->VideoCtx; frame = decoder->Frame; @@ -491,6 +507,24 @@ next_part: } if (got_frame) { // frame completed +#ifdef YADIF + if (decoder->filter ) { + if (decoder->filter == 1) { + if (init_filters(video_ctx,decoder->HwDecoder,frame) < 0) { + Error(_("video: Init of YADIF Filter failed\n")); + } + else { + Debug(3,"Init YADIF ok\n"); + } + decoder->filter = 2; + } + if (frame->interlaced_frame && decoder->filter == 2 && (frame->height != 720)) { // broken ZDF sends Interlaced flag + ret = push_filters(video_ctx,decoder->HwDecoder,frame); + av_frame_unref(frame); + continue; + } + } +#endif #ifdef FFMPEG_WORKAROUND_ARTIFACTS if (!CodecUsePossibleDefectFrames && decoder->FirstKeyFrame) { decoder->FirstKeyFrame++; diff --git a/codec.h b/codec.h index 987dc39..3b61c5a 100644 --- a/codec.h +++ b/codec.h @@ -62,7 +62,9 @@ struct _video_decoder_ int FirstKeyFrame; ///< flag first frame //#endif AVFrame *Frame; ///< decoded video frame - +#ifdef YADIF + int filter; // flag for yadif filter +#endif /* hwaccel options */ enum HWAccelID hwaccel_id; char *hwaccel_device; diff --git a/misc.h b/misc.h index 419df66..de29cc5 100644 --- a/misc.h +++ b/misc.h @@ -160,7 +160,7 @@ static inline uint64_t GetusTicks(void) struct timespec tspec; clock_gettime(CLOCK_MONOTONIC, &tspec); - return (tspec.tv_sec * 1000000) + (tspec.tv_nsec) ; + return (uint64_t) (tspec.tv_sec * 1000000) + (tspec.tv_nsec) ; #else struct timeval tval; diff --git a/softhdcuvid.cpp b/softhdcuvid.cpp index 51838f1..cdaf47f 100644 --- a/softhdcuvid.cpp +++ b/softhdcuvid.cpp @@ -992,13 +992,12 @@ void cMenuSetupSoft::Create(void) static const char *const video_display_formats_16_9[] = { "pan&scan", "pillarbox", "center cut-out", }; -#if 0 +#ifdef YADIF static const char *const deinterlace[] = { - "Bob", "Weave/None", "Temporal", "TemporalSpatial", "Software Bob", - "Software Spatial", + "Cuda", "Yadif", }; static const char *const deinterlace_short[] = { - "B", "W", "T", "T+S", "S+B", "S+S", + "C", "Y", }; #endif @@ -1006,7 +1005,7 @@ void cMenuSetupSoft::Create(void) "None", "PCM", "AC-3", "PCM + AC-3" }; static const char *const resolution[RESOLUTIONS] = { - "576", "720", "fake 1080", "1080" ,"UHD" + "576i", "720p", "fake 1080", "1080" ,"2160p" }; #ifdef PLACEBO static const char *const target_colorspace[] = { @@ -1126,12 +1125,15 @@ void cMenuSetupSoft::Create(void) Add(CollapsedItem(resolution[i], ResolutionShown[i], msg)); if (ResolutionShown[i]) { -#if PLACEBO +#ifdef PLACEBO Add(new cMenuEditStraItem(tr("Scaling"), &Scaling[i], scalers, scaling)); #endif +#ifdef YADIF + if ( i == 0 || i == 2 || i == 3) { + Add(new cMenuEditStraItem(tr("Deinterlace"), &Deinterlace[i],2, deinterlace)); + } +#endif #if 0 - Add(new cMenuEditStraItem(tr("Deinterlace"), &Deinterlace[i], - 6, deinterlace)); Add(new cMenuEditBoolItem(tr("SkipChromaDeinterlace (vdpau)"), &SkipChromaDeinterlace[i], trVDR("no"), trVDR("yes"))); Add(new cMenuEditBoolItem(tr("Inverse Telecine (vdpau)"), @@ -3319,58 +3321,58 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value) } #endif for (i = 0; i < RESOLUTIONS; ++i) { - char buf[128]; + char buf[128]; - snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Scaling"); - if (!strcasecmp(name, buf)) { - ConfigVideoScaling[i] = atoi(value); - VideoSetScaling(ConfigVideoScaling); - return true; - } - snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Deinterlace"); - if (!strcasecmp(name, buf)) { - ConfigVideoDeinterlace[i] = atoi(value); - VideoSetDeinterlace(ConfigVideoDeinterlace); - return true; - } - snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], - "SkipChromaDeinterlace"); - if (!strcasecmp(name, buf)) { - ConfigVideoSkipChromaDeinterlace[i] = atoi(value); - VideoSetSkipChromaDeinterlace(ConfigVideoSkipChromaDeinterlace); - return true; - } - snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "InverseTelecine"); - if (!strcasecmp(name, buf)) { - ConfigVideoInverseTelecine[i] = atoi(value); - VideoSetInverseTelecine(ConfigVideoInverseTelecine); - return true; - } - snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Denoise"); - if (!strcasecmp(name, buf)) { - ConfigVideoDenoise[i] = atoi(value); - VideoSetDenoise(ConfigVideoDenoise); - return true; - } - snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Sharpen"); - if (!strcasecmp(name, buf)) { - ConfigVideoSharpen[i] = atoi(value); - VideoSetSharpen(ConfigVideoSharpen); - return true; - } + snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Scaling"); + if (!strcasecmp(name, buf)) { + ConfigVideoScaling[i] = atoi(value); + VideoSetScaling(ConfigVideoScaling); + return true; + } + snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Deinterlace"); + if (!strcasecmp(name, buf)) { + ConfigVideoDeinterlace[i] = atoi(value); + VideoSetDeinterlace(ConfigVideoDeinterlace); + return true; + } + snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], + "SkipChromaDeinterlace"); + if (!strcasecmp(name, buf)) { + ConfigVideoSkipChromaDeinterlace[i] = atoi(value); + VideoSetSkipChromaDeinterlace(ConfigVideoSkipChromaDeinterlace); + return true; + } + snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "InverseTelecine"); + if (!strcasecmp(name, buf)) { + ConfigVideoInverseTelecine[i] = atoi(value); + VideoSetInverseTelecine(ConfigVideoInverseTelecine); + return true; + } + snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Denoise"); + if (!strcasecmp(name, buf)) { + ConfigVideoDenoise[i] = atoi(value); + VideoSetDenoise(ConfigVideoDenoise); + return true; + } + snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Sharpen"); + if (!strcasecmp(name, buf)) { + ConfigVideoSharpen[i] = atoi(value); + VideoSetSharpen(ConfigVideoSharpen); + return true; + } - snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "CutTopBottom"); - if (!strcasecmp(name, buf)) { - ConfigVideoCutTopBottom[i] = atoi(value); - VideoSetCutTopBottom(ConfigVideoCutTopBottom); - return true; - } - snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "CutLeftRight"); - if (!strcasecmp(name, buf)) { - ConfigVideoCutLeftRight[i] = atoi(value); - VideoSetCutLeftRight(ConfigVideoCutLeftRight); - return true; - } + snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "CutTopBottom"); + if (!strcasecmp(name, buf)) { + ConfigVideoCutTopBottom[i] = atoi(value); + VideoSetCutTopBottom(ConfigVideoCutTopBottom); + return true; + } + snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "CutLeftRight"); + if (!strcasecmp(name, buf)) { + ConfigVideoCutLeftRight[i] = atoi(value); + VideoSetCutLeftRight(ConfigVideoCutLeftRight); + return true; + } } if (!strcasecmp(name, "AutoCrop.Interval")) { diff --git a/softhddev.c b/softhddev.c index d211974..1a91fa6 100644 --- a/softhddev.c +++ b/softhddev.c @@ -2219,7 +2219,7 @@ int PlayVideo3(VideoStream * stream, const uint8_t * data, int size) } // hard limit buffer full: needed for replay if (atomic_read(&stream->PacketsFilled) >= VIDEO_PACKET_MAX - 10) { - Debug(3, "video: video buffer full\n"); +// Debug(3, "video: video buffer full\n"); return 0; } #ifdef USE_SOFTLIMIT @@ -2907,7 +2907,7 @@ const char *CommandLineHelp(void) " -d display\tdisplay of x11 server (fe. :0.0)\n" " -f\t\tstart with fullscreen window (only with window manager)\n" " -g geometry\tx11 window geometry wxh+x+y\n" - " -v device\tvideo driver device (va-api, vdpau, noop)\n" + " -v device\tvideo driver device (cuvid)\n" " -s\t\tstart in suspended mode\n" " -x\t\tstart x11 server, with -xx try to connect, if this fails\n" " -X args\tX11 server arguments (f.e. -nocursor)\n" diff --git a/video.c b/video.c index 28d139e..6a58b3f 100644 --- a/video.c +++ b/video.c @@ -41,6 +41,7 @@ //#define PLACEBO + #define USE_XLIB_XCB ///< use xlib/xcb backend #define noUSE_SCREENSAVER ///< support disable screensaver //#define USE_AUTOCROP ///< compile auto-crop support @@ -55,12 +56,23 @@ #endif #define USE_VIDEO_THREAD ///< run decoder in an own thread -//#define USE_VIDEO_THREAD2 ///< run decoder+display in own threads + #include #include #include #include +#include + +#include /* File Control Definitions */ +#include /* POSIX Terminal Control Definitions */ +#include /* UNIX Standard Definitions */ +#include /* ERROR Number Definitions */ +#include /* ioctl() */ +//#include +//#include +//#include +//#inclde #include #include @@ -171,7 +183,7 @@ typedef enum #include // support old ffmpeg versions <1.0 -#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,18,102) +#if 0 //LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,18,102) #define AVCodecID CodecID #define AV_CODEC_ID_H263 CODEC_ID_H263 #define AV_CODEC_ID_H264 CODEC_ID_H264 @@ -185,6 +197,12 @@ typedef enum #include #include +#ifdef YADIF +#include +#include +#include +#endif + #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54,86,100) /// /// ffmpeg version 1.1.1 calls get_format with zero width and height @@ -225,12 +243,8 @@ typedef enum _video_resolutions_ /// typedef enum _video_deinterlace_modes_ { - VideoDeinterlaceBob, ///< bob deinterlace - VideoDeinterlaceWeave, ///< weave deinterlace - VideoDeinterlaceTemporal, ///< temporal deinterlace - VideoDeinterlaceTemporalSpatial, ///< temporal spatial deinterlace - VideoDeinterlaceSoftBob, ///< software bob deinterlace - VideoDeinterlaceSoftSpatial, ///< software spatial deinterlace + VideoDeinterlaceCuda, ///< Cuda build in deinterlace + VideoDeinterlaceYadif, ///< Yadif deinterlace } VideoDeinterlaceModes; /// @@ -327,7 +341,7 @@ typedef struct { #define CODEC_SURFACES_MAX 16 ///< maximal of surfaces #define VIDEO_SURFACES_MAX 8 ///< video output surfaces for queue -#define OUTPUT_SURFACES_MAX 4 ///< output surfaces for flip page +//#define OUTPUT_SURFACES_MAX 4 ///< output surfaces for flip page //---------------------------------------------------------------------------- // Variables @@ -439,14 +453,14 @@ static pthread_mutex_t VideoLockMutex; ///< video lock mutex pthread_mutex_t OSDMutex; ///< OSD update 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 pthread_t VideoDisplayThread; ///< video display thread +//static pthread_cond_t VideoDisplayWakeupCond; ///< wakeup condition variable +//static pthread_mutex_t VideoDisplayMutex; ///< video condition mutex +//static pthread_mutex_t VideoDisplayLockMutex; ///< video lock mutex + + static int OsdConfigWidth; ///< osd configured width static int OsdConfigHeight; ///< osd configured height @@ -554,9 +568,7 @@ static void VideoSetPts(int64_t * pts_p, int interlaced, if (delta > -600 * 90 && delta <= -40 * 90) { if (-delta > VideoDeltaPTS) { VideoDeltaPTS = -delta; - Debug(4, - "video: %#012" PRIx64 "->%#012" PRIx64 " delta%+4" - PRId64 " pts\n", *pts_p, pts, pts - *pts_p); + Debug(4,"video: %#012" PRIx64 "->%#012" PRIx64 " delta%+4" PRId64 " pts\n", *pts_p, pts, pts - *pts_p); } return; } @@ -564,9 +576,7 @@ static void VideoSetPts(int64_t * pts_p, int interlaced, AudioVideoReady(pts); } if (*pts_p != pts) { - Debug(4, - "video: %#012" PRIx64 "->%#012" PRIx64 " delta=%4" PRId64 - " pts\n", *pts_p, pts, pts - *pts_p); + Debug(4,"video: %#012" PRIx64 "->%#012" PRIx64 " delta=%4" PRId64" pts\n", *pts_p, pts, pts - *pts_p); *pts_p = pts; } } @@ -1043,7 +1053,7 @@ static void GlxSetupWindow(xcb_window_t window, int width, int height, GLXContex unsigned count; #endif -#ifdef PLACEBO +#ifdef PLACEBO_ return; #endif @@ -1658,7 +1668,7 @@ typedef struct _cuvid_decoder_ CUcontext cuda_ctx; #ifdef PLACEBO - struct pl_image pl_images[CODEC_SURFACES_MAX+1]; // images f�r Placebo chain + struct pl_image pl_images[CODEC_SURFACES_MAX+1]; // images for Placebo chain const struct pl_tex *pl_tex_in[CODEC_SURFACES_MAX+1][2]; // Textures in image const struct pl_buf *pl_buf_Y,*pl_buf_UV; // buffer for Texture upload struct ext_buf ebuf[2]; // for managing vk buffer @@ -1673,6 +1683,12 @@ typedef struct _cuvid_decoder_ int Closing; ///< flag about closing current stream int SyncOnAudio; ///< flag sync to audio int64_t PTS; ///< video PTS clock + +#ifdef YADIF + AVFilterContext *buffersink_ctx; + AVFilterContext *buffersrc_ctx; + AVFilterGraph *filter_graph; +#endif int LastAVDiff; ///< last audio - video difference int SyncCounter; ///< counter to sync frames @@ -1703,10 +1719,14 @@ typedef struct priv { struct pl_render_params r_params; struct pl_tex final_fbo; VkSurfaceKHR pSurface; + VkSemaphore sig_in; }priv; static priv *p; static struct pl_overlay osdoverlay; +static int semid; +struct itimerval itimer; + #endif @@ -1985,7 +2005,7 @@ static CuvidDecoder *CuvidNewHwDecoder(VideoStream * stream) CuvidDecoder *decoder; int i=0; - setenv ("DISPLAY", ":0", 0); +// setenv ("DISPLAY", ":0", 0); Debug(3,"Cuvid New HW Decoder\n"); if ((unsigned)CuvidDecoderN >= sizeof(CuvidDecoders) / sizeof(*CuvidDecoders)) { @@ -2256,7 +2276,7 @@ createTextureDst(CuvidDecoder * decoder,int anz, unsigned int size_x, unsigned i img->num_overlays = 0; } - decoder->pl_buf_Y = pl_buf_create(p->gpu, &(struct pl_buf_params) { // buffer f�r Y texture upload + decoder->pl_buf_Y = pl_buf_create(p->gpu, &(struct pl_buf_params) { // buffer for Y texture upload .type = PL_BUF_TEX_TRANSFER, .size = size_x * size_y * size, .host_mapped = false, @@ -2265,9 +2285,8 @@ createTextureDst(CuvidDecoder * decoder,int anz, unsigned int size_x, unsigned i .handle_type = PL_HANDLE_FD, }); decoder->ebuf[0].fd = dup(decoder->pl_buf_Y->shared_mem.handle.fd); // dup fd -// printf("Y Offset %d Size %d FD %d\n",decoder->pl_buf_Y->handle_offset,decoder->pl_buf_Y->handles.size,decoder->pl_buf_Y->handles.fd); - decoder->pl_buf_UV = pl_buf_create(p->gpu, &(struct pl_buf_params) { // buffer f�r UV texture upload + decoder->pl_buf_UV = pl_buf_create(p->gpu, &(struct pl_buf_params) { // buffer for UV texture upload .type = PL_BUF_TEX_TRANSFER, .size = size_x * size_y * size / 2, .host_mapped = false, @@ -2277,9 +2296,7 @@ createTextureDst(CuvidDecoder * decoder,int anz, unsigned int size_x, unsigned i }); decoder->ebuf[1].fd = dup(decoder->pl_buf_UV->shared_mem.handle.fd); // dup fd -// printf("UV Offset %d Size %d FD %d\n",decoder->pl_buf_UV->handle_offset,decoder->pl_buf_UV->handles.size,decoder->pl_buf_UV->handles.fd); - - CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc = { + CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc = { .type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD, .handle.fd = decoder->ebuf[0].fd, .size = decoder->pl_buf_Y->shared_mem.size, // image_width * image_height * bytes, @@ -2309,7 +2326,6 @@ createTextureDst(CuvidDecoder * decoder,int anz, unsigned int size_x, unsigned i }; checkCudaErrors(cuExternalMemoryGetMappedBuffer(&decoder->ebuf[1].buf, decoder->ebuf[1].mem, &buf_desc1)); // get pointer -//printf("generate textures %d %d\n",size_x,size_y); } @@ -2468,6 +2484,145 @@ static unsigned CuvidGetVideoSurface(CuvidDecoder * decoder, return CuvidGetVideoSurface0(decoder); } +#ifdef YADIF +static void CuvidSyncRenderFrame(CuvidDecoder * decoder, + const AVCodecContext * video_ctx, const AVFrame * frame); + +int push_filters(AVCodecContext * dec_ctx,CuvidDecoder * decoder,AVFrame *frame) { + int ret; + AVFrame *filt_frame = av_frame_alloc(); + +// frame->pts = frame->best_effort_timestamp; + + /* push the decoded frame into the filtergraph */ + if (av_buffersrc_add_frame_flags(decoder->buffersrc_ctx, frame, AV_BUFFERSRC_FLAG_KEEP_REF) < 0) { + av_log(NULL, AV_LOG_ERROR, "Error while feeding the filtergraph\n"); + } + +//printf("Interlaced %d tff %d\n",frame->interlaced_frame,frame->top_field_first); + /* pull filtered frames from the filtergraph */ + while ((ret = av_buffersink_get_frame(decoder->buffersink_ctx, filt_frame)) >= 0) { +// filt_frame->pts = frame->pts; // Restore orginal pts +// frame->pts += 20 * 90; // prepare for next frame + filt_frame->pts /= 2; +// Debug(3,"video:new %#012" PRIx64 " old %#012" PRIx64 "\n",filt_frame->pts,frame->pts); + CuvidSyncRenderFrame(decoder, dec_ctx, filt_frame); + av_frame_unref(filt_frame); + } + + av_frame_free(&filt_frame); + return ret; +} + + +int init_filters(AVCodecContext * dec_ctx,CuvidDecoder * decoder,AVFrame *frame) +{ + const char *filters_descr = "yadif_cuda=1:0:1"; // mode=send_field,parity=tff,deint=interlaced"; + char args[512]; + int ret = 0; + const AVFilter *buffersrc = avfilter_get_by_name("buffer"); + const AVFilter *buffersink = avfilter_get_by_name("buffersink"); + AVFilterInOut *outputs = avfilter_inout_alloc(); + AVFilterInOut *inputs = avfilter_inout_alloc(); + AVBufferSrcParameters *src_params; + enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_CUDA, AV_PIX_FMT_NONE }; + + if (decoder->filter_graph) + avfilter_graph_free(&decoder->filter_graph); + + decoder->filter_graph = avfilter_graph_alloc(); + if (!outputs || !inputs || !decoder->filter_graph) { + ret = AVERROR(ENOMEM); + goto end; + } + + /* buffer video source: the decoded frames from the decoder will be inserted here. */ + snprintf(args, sizeof(args), + "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", + dec_ctx->width, dec_ctx->height, AV_PIX_FMT_CUDA, + 1, 90000, + dec_ctx->sample_aspect_ratio.num, dec_ctx->sample_aspect_ratio.den); + + ret = avfilter_graph_create_filter(&decoder->buffersrc_ctx, buffersrc, "in", + args, NULL, decoder->filter_graph); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n"); + goto end; + } + src_params = av_buffersrc_parameters_alloc(); + src_params->hw_frames_ctx = frame->hw_frames_ctx; + src_params->format = AV_PIX_FMT_CUDA; + src_params->time_base.num = 1; + src_params->time_base.den = 90000; + src_params->width = dec_ctx->width; + src_params->height = dec_ctx->height; + src_params->frame_rate.num = 50; + src_params->frame_rate.den = 1; + src_params->sample_aspect_ratio = dec_ctx->sample_aspect_ratio; + +//printf("width %d height %d hw_frames_ctx %p\n",dec_ctx->width,dec_ctx->height ,frame->hw_frames_ctx); + ret = av_buffersrc_parameters_set(decoder->buffersrc_ctx, src_params); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Cannot set hw_frames_ctx to src\n"); + goto end; + } + /* buffer video sink: to terminate the filter chain. */ + ret = avfilter_graph_create_filter(&decoder->buffersink_ctx, buffersink, "out", + NULL, NULL, decoder->filter_graph); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n"); + goto end; + } + + ret = av_opt_set_int_list(decoder->buffersink_ctx, "pix_fmts", pix_fmts, + AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Cannot set output pixel format\n"); + goto end; + } + + /* + * Set the endpoints for the filter graph. The filter_graph will + * be linked to the graph described by filters_descr. + */ + + /* + * The buffer source output must be connected to the input pad of + * the first filter described by filters_descr; since the first + * filter input label is not specified, it is set to "in" by + * default. + */ + outputs->name = av_strdup("in"); + outputs->filter_ctx = decoder->buffersrc_ctx; + outputs->pad_idx = 0; + outputs->next = NULL; + + /* + * The buffer sink input must be connected to the output pad of + * the last filter described by filters_descr; since the last + * filter output label is not specified, it is set to "out" by + * default. + */ + inputs->name = av_strdup("out"); + inputs->filter_ctx = decoder->buffersink_ctx; + inputs->pad_idx = 0; + inputs->next = NULL; + + if ((ret = avfilter_graph_parse_ptr(decoder->filter_graph, filters_descr, + &inputs, &outputs, NULL)) < 0) + goto end; + + if ((ret = avfilter_graph_config(decoder->filter_graph, NULL)) < 0) + goto end; + +end: + avfilter_inout_free(&inputs); + avfilter_inout_free(&outputs); + + return ret; +} + +#endif typedef struct CUVIDContext { @@ -2487,7 +2642,7 @@ static enum AVPixelFormat Cuvid_get_format(CuvidDecoder * decoder, AVCodecContext * video_ctx, const enum AVPixelFormat *fmt) { const enum AVPixelFormat *fmt_idx; - int bitformat16 = 0; + int bitformat16 = 0,deint=0; VideoDecoder *ist = video_ctx->opaque; @@ -2514,7 +2669,7 @@ static enum AVPixelFormat Cuvid_get_format(CuvidDecoder * decoder, } break; } - + Debug(3,"video profile %d codec id %d\n",video_ctx->profile,video_ctx->codec_id); if (*fmt_idx == AV_PIX_FMT_NONE) { Error(_("video: no valid pixfmt found\n")); @@ -2537,9 +2692,10 @@ static enum AVPixelFormat Cuvid_get_format(CuvidDecoder * decoder, decoder->PixFmt = AV_PIX_FMT_NV12; // 8 Bit Planar ist->hwaccel_output_format = AV_PIX_FMT_NV12; } - - if ( video_ctx->width != decoder->InputWidth - || video_ctx->height != decoder->InputHeight) { +#if 1 + if (1 || video_ctx->width != decoder->InputWidth + || video_ctx->height != decoder->InputHeight) { + CuvidCleanup(decoder); decoder->InputAspect = video_ctx->sample_aspect_ratio; decoder->InputWidth = video_ctx->width; @@ -2551,8 +2707,23 @@ static enum AVPixelFormat Cuvid_get_format(CuvidDecoder * decoder, #ifdef PLACEBO // dont show first frame decoder->newchannel = 1; #endif - } - +#ifdef YADIF + if (VideoDeinterlace[decoder->Resolution] == VideoDeinterlaceYadif) { + deint = 0; + ist->filter = 1; // init yadif_cuda + } + else { + deint = 2; + ist->filter = 0; + } + CuvidMessage(2,"deint = %s\n",deint==0?"Yadif":"Cuda"); + if (av_opt_set_int(video_ctx->priv_data, "deint", deint ,0) < 0) { // adaptive + Fatal(_("codec: can't set option deint to video codec!\n")); + } +#endif + } + +#endif CuvidMessage(2,"CUVID Init ok %dx%d\n",video_ctx->width,video_ctx->height); ist->active_hwaccel_id = HWACCEL_CUVID; ist->hwaccel_pix_fmt = AV_PIX_FMT_CUDA; @@ -3161,7 +3332,7 @@ static void CuvidRenderFrame(CuvidDecoder * decoder, video_ctx->width != decoder->InputWidth // || decoder->ColorSpace != color || video_ctx->height != decoder->InputHeight) { -Debug(3,"fmt %02d:%02d width %d:%d hight %d:%d\n",decoder->ColorSpace,frame->colorspace ,video_ctx->width, decoder->InputWidth,video_ctx->height, decoder->InputHeight); +//Debug(3,"fmt %02d:%02d width %d:%d hight %d:%d\n",decoder->ColorSpace,frame->colorspace ,video_ctx->width, decoder->InputWidth,video_ctx->height, decoder->InputHeight); decoder->InputWidth = video_ctx->width; decoder->InputHeight = video_ctx->height; @@ -3188,8 +3359,7 @@ Debug(3,"fmt %02d:%02d width %d:%d hight %d:%d\n",decoder->ColorSpace,frame->co surface = CuvidGetVideoSurface0(decoder); if (surface == -1) // no free surfaces - return; - + return; #if 0 // old copy via host ram { @@ -3526,10 +3696,10 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))int lev decoder->newchannel = 0; if (!pl_render_image(p->renderer, &decoder->pl_images[current], target, &render_params)) { - Fatal(_("Failed rendering frame!\n")); + Debug(3,"Failed rendering frame!\n"); } - if (VideoScalerTest) { // left side internal scaler (bicubic) + if (VideoScalerTest) { // left side test scaler // Source crop img->src_rect.x0 = video_src_rect.x0; img->src_rect.y0 = video_src_rect.y0; @@ -3548,7 +3718,7 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))int lev p->renderertest = pl_renderer_create(p->ctx, p->gpu); if (!pl_render_image(p->renderertest, &decoder->pl_images[current], target, &render_params)) { - Fatal(_("Failed rendering frame!\n")); + Debug(3,"Failed rendering frame!\n"); } } else if (p->renderertest) { @@ -3556,6 +3726,7 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))int lev p->renderertest = NULL; } #endif + Debug(4, "video/vdpau: yy video surface %p displayed\n", current, decoder->SurfaceRead); } @@ -3624,15 +3795,19 @@ static void CuvidDisplayFrame(void) static unsigned int Count; int filled; CuvidDecoder *decoder; + int RTS_flag; + + #ifdef PLACEBO uint64_t diff; struct pl_swapchain_frame frame; struct pl_render_target target; bool ok; + VkImage Image; + const struct pl_fmt *fmt; const float black[4] = { 0.0f,0.0f,0.0f,1.0f}; - #endif - + #ifndef PLACEBO glXMakeCurrent(XlibDisplay, VideoWindow, GlxContext); @@ -3645,27 +3820,45 @@ static void CuvidDisplayFrame(void) glXWaitVideoSyncSGI (2, (Count + 1) % 2, &Count); // wait for previous frame to swap last_time = GetusTicks(); glClear(GL_COLOR_BUFFER_BIT); -#else +#else + if (CuvidDecoderN) + CuvidDecoders[0]->Frameproc = (float)(GetusTicks()-last_time)/1000000.0; +#if 0 diff = (GetusTicks()-last_time)/1000000; // printf("Time wait %2.2f \n",(float)(diff)); last_time = GetusTicks(); - + if (diff < 19) { +// printf("Sleep %d\n",19-diff); +// usleep((18 - diff) * 1000); + } +// usleep(15000); +// printf("sleept %d\n",(GetusTicks()-last_time)/1000000); - - pl_swapchain_swap_buffers(p->swapchain); // swap buffers - -// printf(" Latency %d Time wait %2.2f\n",pl_swapchain_latency(p->swapchain),(float)(GetusTicks()-last_time)/1000000.0); - last_time = GetusTicks(); +// last_time = GetusTicks(); +#endif if (!p->swapchain) return; - usleep(1000); - if (!pl_swapchain_start_frame(p->swapchain, &frame)) { // get new frame - usleep(10); - } +// pl_swapchain_swap_buffers(p->swapchain); // swap buffers + +// printf(" Latency %d \n",pl_swapchain_latency(p->swapchain)); +// last_time = GetusTicks(); + + + pthread_mutex_unlock(&VideoLockMutex); + + while (!pl_swapchain_start_frame(p->swapchain, &frame)) { // get new frame wait for previous to swap + usleep(5); + } + pthread_mutex_lock(&VideoLockMutex); + +last_time = GetusTicks(); + if (!frame.fbo) + return; pl_render_target_from_swapchain(&target, &frame); // make target frame + if (VideoSurfaceModesChanged){ pl_renderer_destroy(&p->renderer); p->renderer = pl_renderer_create(p->ctx, p->gpu); @@ -3685,8 +3878,8 @@ static void CuvidDisplayFrame(void) // target.repr.bits.sample_depth = 16; // target.repr.bits.color_depth = 16; // target.repr.bits.bit_shift =0; +// pl_tex_clear(p->gpu,target.fbo,(float[4]){0}); - pl_tex_clear(p->gpu,target.fbo,(float[4]){0}); switch (VulkanTargetColorSpace) { case 0: memcpy(&target.color,&pl_color_space_monitor,sizeof(struct pl_color_space)); @@ -3726,15 +3919,19 @@ static void CuvidDisplayFrame(void) // need 1 frame for progressive, 3 frames for interlaced if (filled < 1 + 2 * decoder->Interlaced) { // FIXME: rewrite MixVideo to support less surfaces - if ((VideoShowBlackPicture && !decoder->TrickSpeed) || (VideoShowBlackPicture && decoder->Closing < -300)) { + if ((VideoShowBlackPicture && !decoder->TrickSpeed) || + (VideoShowBlackPicture && decoder->Closing < -300)) { // || +// (!decoder->TrickSpeed && decoder->newchannel)) { CuvidBlackSurface(decoder); +#ifdef PLACEBO + pl_tex_clear(p->gpu,target.fbo,(float[4]){0}); +#endif CuvidMessage(3, "video/cuvid: black surface displayed\n"); } continue; } #ifdef PLACEBO if (OsdShown == 1) { // New OSD opened -// VideoSetAbove(); pthread_mutex_lock(&OSDMutex); make_osd_overlay(OSDx,OSDy,OSDxsize,OSDysize); if (posd) { @@ -3748,12 +3945,11 @@ static void CuvidDisplayFrame(void) } if (OsdShown == 2) { -// VideoSetAbove(); CuvidMixVideo(decoder, i, &target, &osdoverlay); } else { + CuvidMixVideo(decoder, i, &target, NULL); - } - + } #else CuvidMixVideo(decoder, i); #endif @@ -3795,13 +3991,9 @@ static void CuvidDisplayFrame(void) #endif #ifdef PLACEBO - if (!pl_swapchain_submit_frame(p->swapchain)) - Fatal(_("Failed to submit swapchain buffer\n")); - - if (CuvidDecoderN) - CuvidDecoders[0]->Frameproc = (float)(GetusTicks()-last_time)/1000000.0; - + Fatal(_("Failed to submit swapchain buffer\n")); + pl_swapchain_swap_buffers(p->swapchain); // swap buffers #else glXGetVideoSyncSGI (&Count); // get current frame glXSwapBuffers(XlibDisplay, VideoWindow); @@ -3815,7 +4007,7 @@ static void CuvidDisplayFrame(void) // remember time of last shown surface CuvidDecoders[i]->FrameTime = CuvidFrameTime; } -// xcb_flush(Connection); + } /// @@ -3975,7 +4167,10 @@ static void CuvidSyncDecoder(CuvidDecoder * decoder) if (decoder->SyncCounter && decoder->SyncCounter--) { goto skip_sync; } - + +//if (video_clock == (int64_t) AV_NOPTS_VALUE) +// printf("no video pts\n"); + if (audio_clock != (int64_t) AV_NOPTS_VALUE && video_clock != (int64_t) AV_NOPTS_VALUE) { // both clocks are known @@ -3984,10 +4179,12 @@ static void CuvidSyncDecoder(CuvidDecoder * decoder) diff = video_clock - audio_clock - VideoAudioDelay; diff = (decoder->LastAVDiff + diff) / 2; decoder->LastAVDiff = diff; -//if (abs(diff/90) > 30) +//if (abs(diff/90) > 100) // printf("Diff %d\n",diff/90); if (abs(diff) > 5000 * 90) { // more than 5s err = CuvidMessage(2, "video: audio/video difference too big\n"); + decoder->SyncCounter = 1; + goto out; } 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\n"); @@ -4153,6 +4350,7 @@ Debug(3,"Set video mode %dx%d\n",VideoWindowWidth,VideoWindowHeight); #ifdef PLACEBO +#if 0 // delete swapchain if(p->swapchain) pl_swapchain_destroy(&p->swapchain);; @@ -4167,6 +4365,7 @@ Debug(3,"Set video mode %dx%d\n",VideoWindowWidth,VideoWindowHeight); if (!p->swapchain) { Fatal(_("Failed creating vulkan swapchain!")); } +#endif #endif @@ -4181,11 +4380,9 @@ Debug(3,"Set video mode %dx%d\n",VideoWindowWidth,VideoWindowHeight); } } -#ifdef USE_VIDEO_THREAD2 -#else -#ifdef USE_VIDEO_THREAD + /// /// Handle a CUVID display. @@ -4231,7 +4428,7 @@ static void CuvidDisplayHandlerThread(void) } } #ifdef PLACEBO - usleep(100); +// usleep(1000); #endif continue; } @@ -4239,11 +4436,12 @@ static void CuvidDisplayHandlerThread(void) } pthread_mutex_unlock(&VideoLockMutex); - +#if 1 if (!decoded) { // nothing decoded, sleep // FIXME: sleep on wakeup usleep(1 * 100); } +#endif #ifdef PLACEBO usleep(100); #endif @@ -4259,19 +4457,14 @@ static void CuvidDisplayHandlerThread(void) return; } } - +#ifndef PLACEBO pthread_mutex_lock(&VideoLockMutex); CuvidSyncDisplayFrame(); pthread_mutex_unlock(&VideoLockMutex); +#endif + return; } -#else - -#define CuvidDisplayHandlerThread NULL - -#endif - -#endif /// /// Set video output position. @@ -4853,6 +5046,7 @@ void VideoSetVideoEventCallback(void (*videoEventCallback)(void)) /// static void VideoThreadLock(void) { + if (VideoThread) { if (pthread_mutex_lock(&VideoLockMutex)) { Error(_("video: can't lock thread\n")); @@ -4887,19 +5081,22 @@ void pl_log_intern(void *stream, enum pl_log_level level, const char *msg) printf("%5s: %s\n", prefix[level], msg); } - - void InitPlacebo(){ struct pl_vulkan_params params; struct pl_vk_inst_params iparams = pl_vk_inst_default_params; VkXcbSurfaceCreateInfoKHR xcbinfo; + + char xcbext[] = {"VK_KHR_xcb_surface"}; char surfext[] = {"VK_KHR_surface"}; Debug(3,"Init Placebo\n"); + + + p = calloc(1,sizeof(struct priv)); if (!p) Fatal(_("Cant get memory for PLACEBO struct")); @@ -4919,9 +5116,9 @@ void InitPlacebo(){ // iparams.debug = true; iparams.num_extensions = 2; iparams.extensions = malloc(2 * sizeof(const char *)); - *iparams.extensions = xcbext; + *iparams.extensions = surfext; iparams.debug = false; - *(iparams.extensions+1) = surfext; + *(iparams.extensions+1) = xcbext; p->vk_inst = pl_vk_inst_create(p->ctx, &iparams); @@ -4943,16 +5140,16 @@ void InitPlacebo(){ params.instance = p->vk_inst->instance; params.async_transfer = true; params.async_compute = true; -// params.queue_count = 8; + params.queue_count = 1; params.surface = p->pSurface; - params.allow_software = true; + params.allow_software = false; p->vk = pl_vulkan_create(p->ctx, ¶ms); if (!p->vk) Fatal(_("Failed to create Vulkan Device")); p->gpu = p->vk->gpu; - + // Create initial swapchain p->swapchain = pl_vulkan_create_swapchain(p->vk, &(struct pl_vulkan_swapchain_params) { .surface = p->pSurface, @@ -4963,7 +5160,7 @@ void InitPlacebo(){ if (!p->swapchain) { Fatal(_("Failed creating vulkan swapchain!")); } - + // create renderer p->renderer = pl_renderer_create(p->ctx, p->gpu); if (!p->renderer) { @@ -4984,7 +5181,7 @@ static void *VideoDisplayHandlerThread(void *dummy) CUcontext cuda_ctx; #ifdef PLACEBO_ - InitPlacebo(); +// InitPlacebo(); #endif prctl(PR_SET_NAME,"cuvid video",0,0,0); @@ -5001,14 +5198,14 @@ static void *VideoDisplayHandlerThread(void *dummy) GlxSetupWindow(VideoWindow, VideoWindowWidth, VideoWindowHeight, GlxThreadContext); } - for (;;) { // fix dead-lock with CuvidExit pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_testcancel(); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); +#ifndef PLACEBO VideoPollEvent(); - +#endif VideoUsedModule->DisplayHandlerThread(); } @@ -5029,6 +5226,32 @@ static void *VideoDisplayHandlerThread(void *dummy) return dummy; } +#ifdef PLACEBO +static void *VideoHandlerThread(void *dummy) { + CuvidDecoder *decoder; + int filled; + + decoder = CuvidDecoders[0]; + + prctl(PR_SET_NAME,"cuvid video display",0,0,0); + for (;;) { + + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + pthread_testcancel(); + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + + VideoPollEvent(); + usleep(2000); + filled = atomic_read(&decoder->SurfacesFilled); +// if (filled >= 0) { + pthread_mutex_lock(&VideoLockMutex); + CuvidSyncDisplayFrame(); + pthread_mutex_unlock(&VideoLockMutex); +// } + } + return dummy; +} +#endif /// /// Initialize video threads. /// @@ -5043,6 +5266,11 @@ static void VideoThreadInit(void) pthread_mutex_init(&OSDMutex, NULL); pthread_cond_init(&VideoWakeupCond, NULL); pthread_create(&VideoThread, NULL, VideoDisplayHandlerThread, NULL); +#ifdef PLACEBO + pthread_create(&VideoDisplayThread, NULL, VideoHandlerThread, NULL); +#else + VideoDisplayThread = 0; +#endif } /// @@ -5054,15 +5282,25 @@ static void VideoThreadExit(void) void *retval; Debug(3, "video: video thread canceled\n"); - //VideoThreadLock(); + // FIXME: can't cancel locked if (pthread_cancel(VideoThread)) { Error(_("video: can't queue cancel video display thread\n")); } - //VideoThreadUnlock(); + if (pthread_join(VideoThread, &retval) || retval != PTHREAD_CANCELED) { Error(_("video: can't cancel video display thread\n")); } + if (VideoDisplayThread) { + if (pthread_cancel(VideoDisplayThread)) { + Error(_("video: can't queue cancel video display thread\n")); + } + + if (pthread_join(VideoDisplayThread, &retval) || retval != PTHREAD_CANCELED) { + Error(_("video: can't cancel video display thread\n")); + } + VideoDisplayThread = 0; + } VideoThread = 0; pthread_cond_destroy(&VideoWakeupCond); pthread_mutex_destroy(&VideoLockMutex); @@ -6098,11 +6336,11 @@ void VideoSetAbove() /// void VideoSetDeinterlace(int mode[VideoResolutionMax]) { - VideoDeinterlace[0] = mode[0]; - VideoDeinterlace[1] = mode[1]; - VideoDeinterlace[2] = mode[2]; - VideoDeinterlace[3] = mode[3]; - VideoDeinterlace[4] = mode[4]; + VideoDeinterlace[0] = mode[0]; // 576i + VideoDeinterlace[1] = 1; //mode[1]; // 720p + VideoDeinterlace[2] = mode[2]; // fake 1080 + VideoDeinterlace[3] = mode[3]; // 1080 + VideoDeinterlace[4] = 1, //mode[4]; 2160p VideoSurfaceModesChanged = 1; } @@ -6500,11 +6738,11 @@ void VideoExit(void) pl_swapchain_destroy(&p->swapchain); vkDestroySurfaceKHR(p->vk_inst->instance, p->pSurface, NULL); pl_vk_inst_destroy(&p->vk_inst); -printf("1\n"); + // pl_vulkan_destroy(&p->vk); -printf("1\n"); + pl_context_destroy(&p->ctx); -printf("1\n"); + free(p); #endif