mirror of
https://projects.vdr-developer.org/git/vdr-plugin-softhddevice.git
synced 2023-10-10 19:16:51 +02:00
Fix software deinterlace with VA-API.
This commit is contained in:
parent
e419742a40
commit
9f668c4750
@ -1,6 +1,7 @@
|
|||||||
User johns
|
User johns
|
||||||
Date:
|
Date:
|
||||||
|
|
||||||
|
Fix software deinterlace with VA-API.
|
||||||
Fix bug: transposed digits 567 should be 576.
|
Fix bug: transposed digits 567 should be 576.
|
||||||
Audio module cleanup:
|
Audio module cleanup:
|
||||||
Alsa + OSS can be included/build at the same time.
|
Alsa + OSS can be included/build at the same time.
|
||||||
|
361
video.c
361
video.c
@ -226,6 +226,8 @@ static int VideoWindowY; ///< video outout window y coordinate
|
|||||||
static unsigned VideoWindowWidth; ///< video output window width
|
static unsigned VideoWindowWidth; ///< video output window width
|
||||||
static unsigned VideoWindowHeight; ///< video output window height
|
static unsigned VideoWindowHeight; ///< video output window height
|
||||||
|
|
||||||
|
static char VideoHardwareDecoder; ///< flag use hardware decoder
|
||||||
|
|
||||||
static char VideoSurfaceModesChanged; ///< flag surface modes changed
|
static char VideoSurfaceModesChanged; ///< flag surface modes changed
|
||||||
|
|
||||||
/// Default deinterlace mode.
|
/// Default deinterlace mode.
|
||||||
@ -943,7 +945,7 @@ struct _vaapi_decoder_
|
|||||||
int Interlaced; ///< ffmpeg interlaced flag
|
int Interlaced; ///< ffmpeg interlaced flag
|
||||||
int TopFieldFirst; ///< ffmpeg top field displayed first
|
int TopFieldFirst; ///< ffmpeg top field displayed first
|
||||||
|
|
||||||
VAImage DeintImages[3]; ///< deinterlace image buffers
|
VAImage DeintImages[5]; ///< deinterlace image buffers
|
||||||
|
|
||||||
VAImage Image[1]; ///< image buffer to update surface
|
VAImage Image[1]; ///< image buffer to update surface
|
||||||
|
|
||||||
@ -996,7 +998,10 @@ static VaapiDecoder *VaapiDecoders[1]; ///< open decoder streams
|
|||||||
static int VaapiDecoderN; ///< number of decoder streams
|
static int VaapiDecoderN; ///< number of decoder streams
|
||||||
|
|
||||||
/// forward display back surface
|
/// forward display back surface
|
||||||
static void VaapiBlackSurface(VaapiDecoder * decoder);
|
static void VaapiBlackSurface(VaapiDecoder *);
|
||||||
|
|
||||||
|
/// forward destroy deinterlace images
|
||||||
|
static void VaapiDestroyDeinterlaceImages(VaapiDecoder *);
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
// VA-API Functions
|
// VA-API Functions
|
||||||
@ -1262,6 +1267,8 @@ static VaapiDecoder *VaapiNewDecoder(void)
|
|||||||
decoder->DeintImages[0].image_id = VA_INVALID_ID;
|
decoder->DeintImages[0].image_id = VA_INVALID_ID;
|
||||||
decoder->DeintImages[1].image_id = VA_INVALID_ID;
|
decoder->DeintImages[1].image_id = VA_INVALID_ID;
|
||||||
decoder->DeintImages[2].image_id = VA_INVALID_ID;
|
decoder->DeintImages[2].image_id = VA_INVALID_ID;
|
||||||
|
decoder->DeintImages[3].image_id = VA_INVALID_ID;
|
||||||
|
decoder->DeintImages[4].image_id = VA_INVALID_ID;
|
||||||
|
|
||||||
decoder->Image->image_id = VA_INVALID_ID;
|
decoder->Image->image_id = VA_INVALID_ID;
|
||||||
|
|
||||||
@ -1371,6 +1378,10 @@ static void VaapiCleanup(VaapiDecoder * decoder)
|
|||||||
if (decoder->SurfaceFreeN || decoder->SurfaceUsedN) {
|
if (decoder->SurfaceFreeN || decoder->SurfaceUsedN) {
|
||||||
VaapiDestroySurfaces(decoder);
|
VaapiDestroySurfaces(decoder);
|
||||||
}
|
}
|
||||||
|
// cleanup images
|
||||||
|
if (decoder->DeintImages[0].image_id != VA_INVALID_ID) {
|
||||||
|
VaapiDestroyDeinterlaceImages(decoder);
|
||||||
|
}
|
||||||
|
|
||||||
decoder->PTS = AV_NOPTS_VALUE;
|
decoder->PTS = AV_NOPTS_VALUE;
|
||||||
}
|
}
|
||||||
@ -1399,7 +1410,6 @@ static void VaapiDelDecoder(VaapiDecoder * decoder)
|
|||||||
Error(_("video/vaapi: can't destroy a surface\n"));
|
Error(_("video/vaapi: can't destroy a surface\n"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// FIXME: decoder->DeintImages
|
|
||||||
#ifdef USE_GLX
|
#ifdef USE_GLX
|
||||||
if (decoder->GlxSurface[0] != VA_INVALID_ID) {
|
if (decoder->GlxSurface[0] != VA_INVALID_ID) {
|
||||||
if (vaDestroySurfaceGLX(VaDisplay, decoder->GlxSurface[0])
|
if (vaDestroySurfaceGLX(VaDisplay, decoder->GlxSurface[0])
|
||||||
@ -1538,6 +1548,8 @@ static void VideoVaapiExit(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Update output for new size or aspect ratio.
|
/// Update output for new size or aspect ratio.
|
||||||
///
|
///
|
||||||
@ -1654,6 +1666,8 @@ static VAEntrypoint VaapiFindEntrypoint(const VAEntrypoint * entrypoints,
|
|||||||
/// it is terminated by -1 as 0 is a valid format, the
|
/// it is terminated by -1 as 0 is a valid format, the
|
||||||
/// formats are ordered by quality.
|
/// formats are ordered by quality.
|
||||||
///
|
///
|
||||||
|
/// @note + 2 surface for software deinterlace
|
||||||
|
///
|
||||||
static enum PixelFormat Vaapi_get_format(VaapiDecoder * decoder,
|
static enum PixelFormat Vaapi_get_format(VaapiDecoder * decoder,
|
||||||
AVCodecContext * video_ctx, const enum PixelFormat *fmt)
|
AVCodecContext * video_ctx, const enum PixelFormat *fmt)
|
||||||
{
|
{
|
||||||
@ -1672,7 +1686,7 @@ static enum PixelFormat Vaapi_get_format(VaapiDecoder * decoder,
|
|||||||
VaapiBlackSurface(decoder);
|
VaapiBlackSurface(decoder);
|
||||||
VaapiCleanup(decoder);
|
VaapiCleanup(decoder);
|
||||||
|
|
||||||
if (getenv("NO_HW")) { // FIXME: make config option
|
if (!VideoHardwareDecoder) { // hardware disabled by config
|
||||||
Debug(3, "codec: hardware acceleration disabled\n");
|
Debug(3, "codec: hardware acceleration disabled\n");
|
||||||
goto slow_path;
|
goto slow_path;
|
||||||
}
|
}
|
||||||
@ -1691,18 +1705,19 @@ static enum PixelFormat Vaapi_get_format(VaapiDecoder * decoder,
|
|||||||
switch (video_ctx->codec_id) {
|
switch (video_ctx->codec_id) {
|
||||||
case CODEC_ID_MPEG2VIDEO:
|
case CODEC_ID_MPEG2VIDEO:
|
||||||
decoder->SurfacesNeeded =
|
decoder->SurfacesNeeded =
|
||||||
CODEC_SURFACES_MPEG2 + VIDEO_SURFACES_MAX;
|
CODEC_SURFACES_MPEG2 + VIDEO_SURFACES_MAX + 2;
|
||||||
p = VaapiFindProfile(profiles, profile_n, VAProfileMPEG2Main);
|
p = VaapiFindProfile(profiles, profile_n, VAProfileMPEG2Main);
|
||||||
break;
|
break;
|
||||||
case CODEC_ID_MPEG4:
|
case CODEC_ID_MPEG4:
|
||||||
case CODEC_ID_H263:
|
case CODEC_ID_H263:
|
||||||
decoder->SurfacesNeeded =
|
decoder->SurfacesNeeded =
|
||||||
CODEC_SURFACES_MPEG4 + VIDEO_SURFACES_MAX;
|
CODEC_SURFACES_MPEG4 + VIDEO_SURFACES_MAX + 2;
|
||||||
p = VaapiFindProfile(profiles, profile_n,
|
p = VaapiFindProfile(profiles, profile_n,
|
||||||
VAProfileMPEG4AdvancedSimple);
|
VAProfileMPEG4AdvancedSimple);
|
||||||
break;
|
break;
|
||||||
case CODEC_ID_H264:
|
case CODEC_ID_H264:
|
||||||
decoder->SurfacesNeeded = CODEC_SURFACES_H264 + VIDEO_SURFACES_MAX;
|
decoder->SurfacesNeeded =
|
||||||
|
CODEC_SURFACES_H264 + VIDEO_SURFACES_MAX + 2;
|
||||||
// try more simple formats, fallback to better
|
// try more simple formats, fallback to better
|
||||||
if (video_ctx->profile == FF_PROFILE_H264_BASELINE) {
|
if (video_ctx->profile == FF_PROFILE_H264_BASELINE) {
|
||||||
p = VaapiFindProfile(profiles, profile_n,
|
p = VaapiFindProfile(profiles, profile_n,
|
||||||
@ -1719,11 +1734,13 @@ static enum PixelFormat Vaapi_get_format(VaapiDecoder * decoder,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CODEC_ID_WMV3:
|
case CODEC_ID_WMV3:
|
||||||
decoder->SurfacesNeeded = CODEC_SURFACES_VC1 + VIDEO_SURFACES_MAX;
|
decoder->SurfacesNeeded =
|
||||||
|
CODEC_SURFACES_VC1 + VIDEO_SURFACES_MAX + 2;
|
||||||
p = VaapiFindProfile(profiles, profile_n, VAProfileVC1Main);
|
p = VaapiFindProfile(profiles, profile_n, VAProfileVC1Main);
|
||||||
break;
|
break;
|
||||||
case CODEC_ID_VC1:
|
case CODEC_ID_VC1:
|
||||||
decoder->SurfacesNeeded = CODEC_SURFACES_VC1 + VIDEO_SURFACES_MAX;
|
decoder->SurfacesNeeded =
|
||||||
|
CODEC_SURFACES_VC1 + VIDEO_SURFACES_MAX + 2;
|
||||||
p = VaapiFindProfile(profiles, profile_n, VAProfileVC1Advanced);
|
p = VaapiFindProfile(profiles, profile_n, VAProfileVC1Advanced);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -1870,6 +1887,7 @@ static void VaapiPutSurfaceX11(VaapiDecoder * decoder, VASurfaceID surface,
|
|||||||
|
|
||||||
// deinterlace
|
// deinterlace
|
||||||
if (interlaced
|
if (interlaced
|
||||||
|
&& VideoDeinterlace[decoder->Resolution] != VideoDeinterlaceSoftware
|
||||||
&& VideoDeinterlace[decoder->Resolution] != VideoDeinterlaceWeave) {
|
&& VideoDeinterlace[decoder->Resolution] != VideoDeinterlaceWeave) {
|
||||||
if (top_field_first) {
|
if (top_field_first) {
|
||||||
if (field) {
|
if (field) {
|
||||||
@ -2054,9 +2072,8 @@ static int VaapiFindImageFormat(VaapiDecoder * decoder,
|
|||||||
// intel: I420 is native format for MPEG-2 decoded surfaces
|
// intel: I420 is native format for MPEG-2 decoded surfaces
|
||||||
// intel: NV12 is native format for H.264 decoded surfaces
|
// intel: NV12 is native format for H.264 decoded surfaces
|
||||||
case PIX_FMT_YUV420P:
|
case PIX_FMT_YUV420P:
|
||||||
fourcc = VA_FOURCC_YV12; // YVU
|
// fourcc = VA_FOURCC_YV12; // YVU
|
||||||
fourcc = VA_FOURCC('I', '4', '2', '0'); // YUV
|
fourcc = VA_FOURCC('I', '4', '2', '0'); // YUV
|
||||||
// FIXME: intel deinterlace ... only supported with nv12
|
|
||||||
break;
|
break;
|
||||||
case PIX_FMT_NV12:
|
case PIX_FMT_NV12:
|
||||||
fourcc = VA_FOURCC_NV12;
|
fourcc = VA_FOURCC_NV12;
|
||||||
@ -2390,9 +2407,10 @@ static void VaapiBob(VaapiDecoder * decoder, VAImage * src, VAImage * dst1,
|
|||||||
Fatal("video/vaapi: can't map the image!\n");
|
Fatal("video/vaapi: can't map the image!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (1) {
|
if (0) { // test all updated
|
||||||
memset(dst1_base, 0x00, dst1->data_size);
|
memset(dst1_base, 0x00, dst1->data_size);
|
||||||
memset(dst2_base, 0x00, dst2->data_size);
|
memset(dst2_base, 0xFF, dst2->data_size);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
for (p = 0; p < src->num_planes; ++p) {
|
for (p = 0; p < src->num_planes; ++p) {
|
||||||
for (y = 0; y < (unsigned)(src->height >> (p != 0)); y += 2) {
|
for (y = 0; y < (unsigned)(src->height >> (p != 0)); y += 2) {
|
||||||
@ -2423,96 +2441,172 @@ static void VaapiBob(VaapiDecoder * decoder, VAImage * src, VAImage * dst1,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Create software deinterlace images.
|
||||||
|
///
|
||||||
|
/// @param decoder VA-API decoder
|
||||||
|
///
|
||||||
|
static void VaapiCreateDeinterlaceImages(VaapiDecoder * decoder)
|
||||||
|
{
|
||||||
|
VAImageFormat format[1];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// NV12, YV12, I420, BGRA
|
||||||
|
// NV12 Y U/V 2x2
|
||||||
|
// YV12 Y V U 2x2
|
||||||
|
// I420 Y U V 2x2
|
||||||
|
|
||||||
|
// Intel needs NV12
|
||||||
|
VaapiFindImageFormat(decoder, PIX_FMT_NV12, format);
|
||||||
|
//VaapiFindImageFormat(decoder, PIX_FMT_YUV420P, format);
|
||||||
|
for (i = 0; i < 5; ++i) {
|
||||||
|
if (vaCreateImage(decoder->VaDisplay, format, decoder->InputWidth,
|
||||||
|
decoder->InputHeight,
|
||||||
|
decoder->DeintImages + i) != VA_STATUS_SUCCESS) {
|
||||||
|
Error(_("video/vaapi: can't create image!\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (1) {
|
||||||
|
VAImage *img;
|
||||||
|
|
||||||
|
img = decoder->DeintImages;
|
||||||
|
Debug(3, "video/vaapi: %c%c%c%c %dx%d*%d\n", img->format.fourcc,
|
||||||
|
img->format.fourcc >> 8, img->format.fourcc >> 16,
|
||||||
|
img->format.fourcc >> 24, img->width, img->height,
|
||||||
|
img->num_planes);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Destroy software deinterlace images.
|
||||||
|
///
|
||||||
|
/// @param decoder VA-API decoder
|
||||||
|
///
|
||||||
|
static void VaapiDestroyDeinterlaceImages(VaapiDecoder * decoder)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 5; ++i) {
|
||||||
|
if (vaDestroyImage(decoder->VaDisplay,
|
||||||
|
decoder->DeintImages[i].image_id) != VA_STATUS_SUCCESS) {
|
||||||
|
Error(_("video/vaapi: can't destroy image!\n"));
|
||||||
|
}
|
||||||
|
decoder->DeintImages[i].image_id = VA_INVALID_ID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Vaapi software deinterlace.
|
/// Vaapi software deinterlace.
|
||||||
///
|
///
|
||||||
static void VaapiCpuDeinterlace(VaapiDecoder * decoder, VASurfaceID surface)
|
/// @param decoder VA-API decoder
|
||||||
|
/// @param surface interlaced hardware surface
|
||||||
|
///
|
||||||
|
static void VaapiCpuDerive(VaapiDecoder * decoder, VASurfaceID surface)
|
||||||
{
|
{
|
||||||
#if 0
|
//
|
||||||
|
// vaPutImage not working, vaDeriveImage
|
||||||
|
//
|
||||||
|
uint32_t tick1;
|
||||||
|
uint32_t tick2;
|
||||||
|
uint32_t tick3;
|
||||||
|
uint32_t tick4;
|
||||||
|
uint32_t tick5;
|
||||||
VAImage image[1];
|
VAImage image[1];
|
||||||
|
VAImage dest1[1];
|
||||||
|
VAImage dest2[1];
|
||||||
VAStatus status;
|
VAStatus status;
|
||||||
VAImageFormat format[1];
|
VASurfaceID out1;
|
||||||
void *image_base;
|
VASurfaceID out2;
|
||||||
int image_derived;
|
|
||||||
|
|
||||||
// release old frame
|
tick1 = GetMsTicks();
|
||||||
// get new frame
|
|
||||||
// deinterlace
|
|
||||||
|
|
||||||
image_derived = 1;
|
|
||||||
if ((status =
|
if ((status =
|
||||||
vaDeriveImage(decoder->VaDisplay, surface,
|
vaDeriveImage(decoder->VaDisplay, surface,
|
||||||
image)) != VA_STATUS_SUCCESS) {
|
image)) != VA_STATUS_SUCCESS) {
|
||||||
image_derived = 0;
|
Error(_("video/vaapi: vaDeriveImage failed %d\n"), status);
|
||||||
Warning(_("video/vaapi: vaDeriveImage failed %d\n"), status);
|
VaapiQueueSurface(decoder, surface, 0);
|
||||||
// NV12, YV12, I420, BGRA
|
VaapiQueueSurface(decoder, surface, 0);
|
||||||
VaapiFindImageFormat(decoder, PIX_FMT_YUV420P, format);
|
return;
|
||||||
if (vaCreateImage(decoder->VaDisplay, format, decoder->InputWidth,
|
|
||||||
decoder->InputHeight, image) != VA_STATUS_SUCCESS) {
|
|
||||||
Fatal(_("video/vaapi: can't create image!\n"));
|
|
||||||
}
|
|
||||||
if (vaGetImage(decoder->VaDisplay, surface, 0, 0, decoder->InputWidth,
|
|
||||||
decoder->InputHeight, image->image_id) != VA_STATUS_SUCCESS) {
|
|
||||||
Fatal(_("video/vaapi: can't get image!\n"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Debug(3, "video/vaapi: %c%c%c%c %dx%d*%d\n", image->format.fourcc,
|
tick2 = GetMsTicks();
|
||||||
|
|
||||||
|
Debug(4, "video/vaapi: %c%c%c%c %dx%d*%d\n", image->format.fourcc,
|
||||||
image->format.fourcc >> 8, image->format.fourcc >> 16,
|
image->format.fourcc >> 8, image->format.fourcc >> 16,
|
||||||
image->format.fourcc >> 24, image->width, image->height,
|
image->format.fourcc >> 24, image->width, image->height,
|
||||||
image->num_planes);
|
image->num_planes);
|
||||||
|
|
||||||
if (vaMapBuffer(decoder->VaDisplay, image->buf,
|
// get a free surfaces
|
||||||
&image_base) != VA_STATUS_SUCCESS) {
|
out1 = VaapiGetSurface(decoder);
|
||||||
Fatal("video/vaapi: can't map the image!\n");
|
if (out1 == VA_INVALID_ID) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
if ((status =
|
||||||
|
vaDeriveImage(decoder->VaDisplay, out1,
|
||||||
|
dest1)) != VA_STATUS_SUCCESS) {
|
||||||
|
Error(_("video/vaapi: vaDeriveImage failed %d\n"), status);
|
||||||
|
}
|
||||||
|
tick3 = GetMsTicks();
|
||||||
|
out2 = VaapiGetSurface(decoder);
|
||||||
|
if (out2 == VA_INVALID_ID) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
if ((status =
|
||||||
|
vaDeriveImage(decoder->VaDisplay, out2,
|
||||||
|
dest2)) != VA_STATUS_SUCCESS) {
|
||||||
|
Error(_("video/vaapi: vaDeriveImage failed %d\n"), status);
|
||||||
|
}
|
||||||
|
tick4 = GetMsTicks();
|
||||||
|
|
||||||
|
VaapiBob(decoder, image, dest1, dest2);
|
||||||
|
tick5 = GetMsTicks();
|
||||||
|
|
||||||
|
if (vaDestroyImage(VaDisplay, image->image_id) != VA_STATUS_SUCCESS) {
|
||||||
|
Error(_("video/vaapi: can't destroy image!\n"));
|
||||||
|
}
|
||||||
|
if (vaDestroyImage(VaDisplay, dest1->image_id) != VA_STATUS_SUCCESS) {
|
||||||
|
Error(_("video/vaapi: can't destroy image!\n"));
|
||||||
|
}
|
||||||
|
if (vaDestroyImage(VaDisplay, dest2->image_id) != VA_STATUS_SUCCESS) {
|
||||||
|
Error(_("video/vaapi: can't destroy image!\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(image_base, 0xff, image->width * image->height);
|
VaapiQueueSurface(decoder, out1, 1);
|
||||||
|
VaapiQueueSurface(decoder, out2, 1);
|
||||||
|
|
||||||
if (vaUnmapBuffer(decoder->VaDisplay, image->buf) != VA_STATUS_SUCCESS) {
|
tick5 = GetMsTicks();
|
||||||
Error(_("video/vaapi: can't unmap image buffer\n"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!image_derived) {
|
Debug(3, "video/vaapi: get=%2d get1=%2d get2=%d deint=%2d\n",
|
||||||
if ((status =
|
tick2 - tick1, tick3 - tick2, tick4 - tick3, tick5 - tick4);
|
||||||
vaPutImage(decoder->VaDisplay, surface, image->image_id, 0, 0,
|
}
|
||||||
image->width, image->height, 0, 0, image->width,
|
|
||||||
image->height)) != VA_STATUS_SUCCESS) {
|
|
||||||
Error("video/vaapi: can't put image %d!\n", status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vaDestroyImage(decoder->VaDisplay, image->image_id);
|
///
|
||||||
#endif
|
/// Vaapi software deinterlace.
|
||||||
|
///
|
||||||
|
/// @param decoder VA-API decoder
|
||||||
|
/// @param surface interlaced hardware surface
|
||||||
|
///
|
||||||
|
static void VaapiCpuPut(VaapiDecoder * decoder, VASurfaceID surface)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// vaPutImage working
|
||||||
|
//
|
||||||
|
uint32_t tick1;
|
||||||
|
uint32_t tick2;
|
||||||
|
uint32_t tick3;
|
||||||
|
uint32_t tick4;
|
||||||
|
uint32_t tick5;
|
||||||
VAImage *img1;
|
VAImage *img1;
|
||||||
VAImage *img2;
|
VAImage *img2;
|
||||||
VAImage *img3;
|
VAImage *img3;
|
||||||
VASurfaceID out1;
|
VASurfaceID out;
|
||||||
VASurfaceID out2;
|
VAStatus status;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Create deinterlace images.
|
// Create deinterlace images.
|
||||||
//
|
//
|
||||||
if (decoder->DeintImages[0].image_id == VA_INVALID_ID) {
|
if (decoder->DeintImages[0].image_id == VA_INVALID_ID) {
|
||||||
VAImageFormat format[1];
|
VaapiCreateDeinterlaceImages(decoder);
|
||||||
int i;
|
|
||||||
|
|
||||||
// NV12, YV12, I420, BGRA
|
|
||||||
// VaapiFindImageFormat(decoder, PIX_FMT_YUV420P, format);
|
|
||||||
|
|
||||||
// Intel needs NV12
|
|
||||||
VaapiFindImageFormat(decoder, PIX_FMT_NV12, format);
|
|
||||||
for (i = 0; i < 3; ++i) {
|
|
||||||
if (vaCreateImage(decoder->VaDisplay, format, decoder->InputWidth,
|
|
||||||
decoder->InputHeight,
|
|
||||||
decoder->DeintImages + i) != VA_STATUS_SUCCESS) {
|
|
||||||
Fatal(_("video/vaapi: can't create image!\n"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
img1 = decoder->DeintImages;
|
|
||||||
Debug(3, "video/vaapi: %c%c%c%c %dx%d*%d\n", img1->format.fourcc,
|
|
||||||
img1->format.fourcc >> 8, img1->format.fourcc >> 16,
|
|
||||||
img1->format.fourcc >> 24, img1->width, img1->height,
|
|
||||||
img1->num_planes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 && vaSyncSurface(decoder->VaDisplay, surface) != VA_STATUS_SUCCESS) {
|
if (0 && vaSyncSurface(decoder->VaDisplay, surface) != VA_STATUS_SUCCESS) {
|
||||||
@ -2523,35 +2617,75 @@ static void VaapiCpuDeinterlace(VaapiDecoder * decoder, VASurfaceID surface)
|
|||||||
img2 = decoder->DeintImages + 1;
|
img2 = decoder->DeintImages + 1;
|
||||||
img3 = decoder->DeintImages + 2;
|
img3 = decoder->DeintImages + 2;
|
||||||
|
|
||||||
|
tick1 = GetMsTicks();
|
||||||
if (vaGetImage(decoder->VaDisplay, surface, 0, 0, decoder->InputWidth,
|
if (vaGetImage(decoder->VaDisplay, surface, 0, 0, decoder->InputWidth,
|
||||||
decoder->InputHeight, img1->image_id) != VA_STATUS_SUCCESS) {
|
decoder->InputHeight, img1->image_id) != VA_STATUS_SUCCESS) {
|
||||||
Fatal(_("video/vaapi: can't get img1!\n"));
|
Error(_("video/vaapi: can't get source image\n"));
|
||||||
|
VaapiQueueSurface(decoder, surface, 0);
|
||||||
|
VaapiQueueSurface(decoder, surface, 0);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
tick2 = GetMsTicks();
|
||||||
|
|
||||||
|
// FIXME: handle top_field_first
|
||||||
|
|
||||||
VaapiBob(decoder, img1, img2, img3);
|
VaapiBob(decoder, img1, img2, img3);
|
||||||
|
tick3 = GetMsTicks();
|
||||||
|
|
||||||
// get a free surface and upload the image
|
// get a free surface and upload the image
|
||||||
out1 = VaapiGetSurface(decoder);
|
out = VaapiGetSurface(decoder);
|
||||||
if (vaPutImage(VaDisplay, out1, img2->image_id, 0, 0, img2->width,
|
if (out == VA_INVALID_ID) {
|
||||||
img2->height, 0, 0, img2->width,
|
abort();
|
||||||
img2->height) != VA_STATUS_SUCCESS) {
|
|
||||||
Error("video/vaapi: can't put image!\n");
|
|
||||||
}
|
}
|
||||||
VaapiQueueSurface(decoder, out1, 1);
|
if ((status =
|
||||||
if (0 && vaSyncSurface(decoder->VaDisplay, out1) != VA_STATUS_SUCCESS) {
|
vaPutImage(VaDisplay, out, img2->image_id, 0, 0, img2->width,
|
||||||
|
img2->height, 0, 0, img2->width,
|
||||||
|
img2->height)) != VA_STATUS_SUCCESS) {
|
||||||
|
Error("video/vaapi: can't put image: %d!\n", status);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
VaapiQueueSurface(decoder, out, 1);
|
||||||
|
if (1 && vaSyncSurface(decoder->VaDisplay, out) != VA_STATUS_SUCCESS) {
|
||||||
Error(_("video/vaapi: vaSyncSurface failed\n"));
|
Error(_("video/vaapi: vaSyncSurface failed\n"));
|
||||||
}
|
}
|
||||||
|
tick4 = GetMsTicks();
|
||||||
|
|
||||||
|
Debug(3, "video/vaapi: deint %d %#010x -> %#010x\n", decoder->SurfaceField,
|
||||||
|
surface, out);
|
||||||
|
|
||||||
// get a free surface and upload the image
|
// get a free surface and upload the image
|
||||||
out2 = VaapiGetSurface(decoder);
|
out = VaapiGetSurface(decoder);
|
||||||
if (vaPutImage(VaDisplay, out2, img3->image_id, 0, 0, img3->width,
|
if (out == VA_INVALID_ID) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
if (vaPutImage(VaDisplay, out, img3->image_id, 0, 0, img3->width,
|
||||||
img3->height, 0, 0, img3->width,
|
img3->height, 0, 0, img3->width,
|
||||||
img3->height) != VA_STATUS_SUCCESS) {
|
img3->height) != VA_STATUS_SUCCESS) {
|
||||||
Error("video/vaapi: can't put image!\n");
|
Error("video/vaapi: can't put image!\n");
|
||||||
}
|
}
|
||||||
VaapiQueueSurface(decoder, out2, 1);
|
VaapiQueueSurface(decoder, out, 1);
|
||||||
if (0 && vaSyncSurface(decoder->VaDisplay, out2) != VA_STATUS_SUCCESS) {
|
if (1 && vaSyncSurface(decoder->VaDisplay, out) != VA_STATUS_SUCCESS) {
|
||||||
Error(_("video/vaapi: vaSyncSurface failed\n"));
|
Error(_("video/vaapi: vaSyncSurface failed\n"));
|
||||||
}
|
}
|
||||||
|
tick5 = GetMsTicks();
|
||||||
|
|
||||||
|
Debug(4, "video/vaapi: get=%2d deint=%2d put1=%2d put2=%2d\n",
|
||||||
|
tick2 - tick1, tick3 - tick2, tick4 - tick3, tick5 - tick4);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Vaapi software deinterlace.
|
||||||
|
///
|
||||||
|
/// @param decoder VA-API decoder
|
||||||
|
/// @param surface interlaced hardware surface
|
||||||
|
///
|
||||||
|
static void VaapiCpuDeinterlace(VaapiDecoder * decoder, VASurfaceID surface)
|
||||||
|
{
|
||||||
|
if (VaapiBuggyIntel) {
|
||||||
|
VaapiCpuDerive(decoder, surface);
|
||||||
|
} else {
|
||||||
|
VaapiCpuPut(decoder, surface);
|
||||||
|
}
|
||||||
// FIXME: must release software input surface
|
// FIXME: must release software input surface
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2618,23 +2752,30 @@ static void VaapiRenderFrame(VaapiDecoder * decoder,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (VideoDeinterlace[decoder->Resolution] == VideoDeinterlaceSoftware
|
// FIXME: should be done by init video_ctx->field_order
|
||||||
&& interlaced) {
|
if (decoder->Interlaced != interlaced
|
||||||
|
|| decoder->TopFieldFirst != frame->top_field_first) {
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// field_order only in git
|
||||||
|
Debug(3, "video/vaapi: interlaced %d top-field-first %d - %d\n",
|
||||||
|
interlaced, frame->top_field_first, video_ctx->field_order);
|
||||||
|
#else
|
||||||
|
Debug(3, "video/vaapi: interlaced %d top-field-first %d\n",
|
||||||
|
interlaced, frame->top_field_first);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
decoder->Interlaced = interlaced;
|
||||||
|
decoder->TopFieldFirst = frame->top_field_first;
|
||||||
|
decoder->SurfaceField = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interlaced
|
||||||
|
&& VideoDeinterlace[decoder->Resolution] ==
|
||||||
|
VideoDeinterlaceSoftware) {
|
||||||
// FIXME: software deinterlace avpicture_deinterlace
|
// FIXME: software deinterlace avpicture_deinterlace
|
||||||
VaapiCpuDeinterlace(decoder, surface);
|
VaapiCpuDeinterlace(decoder, surface);
|
||||||
} else {
|
} else {
|
||||||
// FIXME: should be done by init
|
|
||||||
if (decoder->Interlaced != interlaced
|
|
||||||
|| decoder->TopFieldFirst != frame->top_field_first) {
|
|
||||||
|
|
||||||
Debug(3, "video/vaapi: interlaced %d top-field-first %d\n",
|
|
||||||
interlaced, frame->top_field_first);
|
|
||||||
|
|
||||||
decoder->Interlaced = interlaced;
|
|
||||||
decoder->TopFieldFirst = frame->top_field_first;
|
|
||||||
decoder->SurfaceField = 1;
|
|
||||||
|
|
||||||
}
|
|
||||||
VaapiQueueSurface(decoder, surface, 0);
|
VaapiQueueSurface(decoder, surface, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2694,6 +2835,7 @@ static void VaapiRenderFrame(VaapiDecoder * decoder,
|
|||||||
!= VA_STATUS_SUCCESS) {
|
!= VA_STATUS_SUCCESS) {
|
||||||
Error(_("video/vaapi: can't map the image!\n"));
|
Error(_("video/vaapi: can't map the image!\n"));
|
||||||
}
|
}
|
||||||
|
// FIXME: I420 vs YV12
|
||||||
for (i = 0; (unsigned)i < decoder->Image->num_planes; ++i) {
|
for (i = 0; (unsigned)i < decoder->Image->num_planes; ++i) {
|
||||||
picture->data[i] = va_image_data + decoder->Image->offsets[i];
|
picture->data[i] = va_image_data + decoder->Image->offsets[i];
|
||||||
picture->linesize[i] = decoder->Image->pitches[i];
|
picture->linesize[i] = decoder->Image->pitches[i];
|
||||||
@ -2746,7 +2888,8 @@ static void VaapiAdvanceFrame(void)
|
|||||||
|
|
||||||
// 0 -> 1
|
// 0 -> 1
|
||||||
// 1 -> 0 + advance
|
// 1 -> 0 + advance
|
||||||
if (decoder->Interlaced) {
|
if (VideoDeinterlace[decoder->Resolution] != VideoDeinterlaceSoftware
|
||||||
|
&& decoder->Interlaced) {
|
||||||
// FIXME: first frame is never shown
|
// FIXME: first frame is never shown
|
||||||
if (decoder->SurfaceField) {
|
if (decoder->SurfaceField) {
|
||||||
if (filled > 1) {
|
if (filled > 1) {
|
||||||
@ -2961,7 +3104,7 @@ static void VaapiSyncRenderFrame(VaapiDecoder * decoder,
|
|||||||
}
|
}
|
||||||
// if video output buffer is full, wait and display surface.
|
// if video output buffer is full, wait and display surface.
|
||||||
// loop for interlace
|
// loop for interlace
|
||||||
while (atomic_read(&decoder->SurfacesFilled) >= VIDEO_SURFACES_MAX) {
|
while (atomic_read(&decoder->SurfacesFilled) >= VIDEO_SURFACES_MAX - 1) {
|
||||||
struct timespec abstime;
|
struct timespec abstime;
|
||||||
|
|
||||||
abstime = decoder->FrameTime;
|
abstime = decoder->FrameTime;
|
||||||
@ -3074,7 +3217,7 @@ static void VaapiDisplayHandlerThread(void)
|
|||||||
//
|
//
|
||||||
filled = atomic_read(&decoder->SurfacesFilled);
|
filled = atomic_read(&decoder->SurfacesFilled);
|
||||||
err = 1;
|
err = 1;
|
||||||
if (filled < VIDEO_SURFACES_MAX) {
|
if (filled < VIDEO_SURFACES_MAX - 1) {
|
||||||
// FIXME: hot polling
|
// FIXME: hot polling
|
||||||
pthread_mutex_lock(&VideoLockMutex);
|
pthread_mutex_lock(&VideoLockMutex);
|
||||||
// fetch+decode or reopen
|
// fetch+decode or reopen
|
||||||
@ -4567,7 +4710,7 @@ static enum PixelFormat Vdpau_get_format(VdpauDecoder * decoder,
|
|||||||
Debug(3, "video: new stream format %d\n", GetMsTicks() - VideoSwitch);
|
Debug(3, "video: new stream format %d\n", GetMsTicks() - VideoSwitch);
|
||||||
VdpauCleanup(decoder);
|
VdpauCleanup(decoder);
|
||||||
|
|
||||||
if (getenv("NO_HW")) { // FIXME: make config option
|
if (!VideoHardwareDecoder) { // hardware disabled by config
|
||||||
Debug(3, "codec: hardware acceleration disabled\n");
|
Debug(3, "codec: hardware acceleration disabled\n");
|
||||||
goto slow_path;
|
goto slow_path;
|
||||||
}
|
}
|
||||||
@ -6808,7 +6951,9 @@ void VideoSetOutputPosition(int x, int y, int width, int height)
|
|||||||
///
|
///
|
||||||
/// @note no need to lock, only called from inside the video thread
|
/// @note no need to lock, only called from inside the video thread
|
||||||
///
|
///
|
||||||
void VideoSetVideoMode(int x, int y, int width, int height)
|
void VideoSetVideoMode( __attribute__ ((unused))
|
||||||
|
int x, __attribute__ ((unused))
|
||||||
|
int y, int width, int height)
|
||||||
{
|
{
|
||||||
Debug(3, "video: %s %dx%d%+d%+d\n", __FUNCTION__, width, height, x, y);
|
Debug(3, "video: %s %dx%d%+d%+d\n", __FUNCTION__, width, height, x, y);
|
||||||
if ((unsigned)width == VideoWindowWidth
|
if ((unsigned)width == VideoWindowWidth
|
||||||
@ -7049,6 +7194,10 @@ void VideoInit(const char *display_name)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// FIXME: make it configurable from gui
|
||||||
|
if (!getenv("NO_HW")) {
|
||||||
|
VideoHardwareDecoder = 1;
|
||||||
|
}
|
||||||
//xcb_prefetch_maximum_request_length(Connection);
|
//xcb_prefetch_maximum_request_length(Connection);
|
||||||
xcb_flush(Connection);
|
xcb_flush(Connection);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user