Software deinterlacer (config/skip chroma deint):

Add support for skip chroma deinterlace to software deinterlacer.
Type of software deinterlacer now configurable from setup menu.
This commit is contained in:
Johns 2012-02-09 21:22:42 +01:00
parent 8c16466d31
commit d8f63adaad
3 changed files with 166 additions and 54 deletions

View File

@ -1,6 +1,8 @@
User johns User johns
Date: Date:
Add support for skip chroma deinterlace to software deinterlacer.
Type of software deinterlacer now configurable from setup menu.
Mixer channel could be set through command line option. Mixer channel could be set through command line option.
Fix bug: LFE moved to wrong position. Fix bug: LFE moved to wrong position.
Guard suspend/resume against multiple calls. Guard suspend/resume against multiple calls.

View File

@ -423,7 +423,8 @@ static inline cOsdItem *SeparatorItem(const char *label)
cMenuSetupSoft::cMenuSetupSoft(void) cMenuSetupSoft::cMenuSetupSoft(void)
{ {
static const char *const deinterlace[] = { static const char *const deinterlace[] = {
"Bob", "Weave/None", "Temporal", "TemporalSpatial", "Software" "Bob", "Weave/None", "Temporal", "TemporalSpatial", "Software Bob",
"Software Spatial",
}; };
static const char *const scaling[] = { static const char *const scaling[] = {
"Normal", "Fast", "HQ", "Anamorphic" "Normal", "Fast", "HQ", "Anamorphic"
@ -458,7 +459,7 @@ cMenuSetupSoft::cMenuSetupSoft(void)
Scaling[i] = ConfigVideoScaling[i]; Scaling[i] = ConfigVideoScaling[i];
Add(new cMenuEditStraItem(tr("Scaling"), &Scaling[i], 4, scaling)); Add(new cMenuEditStraItem(tr("Scaling"), &Scaling[i], 4, scaling));
Deinterlace[i] = ConfigVideoDeinterlace[i]; Deinterlace[i] = ConfigVideoDeinterlace[i];
Add(new cMenuEditStraItem(tr("Deinterlace"), &Deinterlace[i], 5, Add(new cMenuEditStraItem(tr("Deinterlace"), &Deinterlace[i], 6,
deinterlace)); deinterlace));
SkipChromaDeinterlace[i] = ConfigVideoSkipChromaDeinterlace[i]; SkipChromaDeinterlace[i] = ConfigVideoSkipChromaDeinterlace[i];
Add(new cMenuEditBoolItem(tr("SkipChromaDeinterlace (vdpau)"), Add(new cMenuEditBoolItem(tr("SkipChromaDeinterlace (vdpau)"),

163
video.c
View File

@ -169,7 +169,8 @@ typedef enum _video_deinterlace_modes_
VideoDeinterlaceWeave, ///< weave deinterlace VideoDeinterlaceWeave, ///< weave deinterlace
VideoDeinterlaceTemporal, ///< temporal deinterlace VideoDeinterlaceTemporal, ///< temporal deinterlace
VideoDeinterlaceTemporalSpatial, ///< temporal spatial deinterlace VideoDeinterlaceTemporalSpatial, ///< temporal spatial deinterlace
VideoDeinterlaceSoftware, ///< software deinterlace VideoDeinterlaceSoftBob, ///< software bob deinterlace
VideoDeinterlaceSoftSpatial, ///< software spatial deinterlace
} VideoDeinterlaceModes; } VideoDeinterlaceModes;
/// ///
@ -1232,6 +1233,7 @@ static void AutoCropDetect(AutoCropCtx * autocrop, int width, int height,
static int VaapiBuggyVdpau; ///< fix libva-driver-vdpau bugs static int VaapiBuggyVdpau; ///< fix libva-driver-vdpau bugs
static int VaapiBuggyIntel; ///< fix libva-driver-intel bugs static int VaapiBuggyIntel; ///< fix libva-driver-intel bugs
static int VaapiNewIntel; ///< new libva-driver-intel driver
static VADisplay *VaDisplay; ///< VA-API display static VADisplay *VaDisplay; ///< VA-API display
@ -1506,7 +1508,7 @@ static VASurfaceID VaapiGetSurface(VaapiDecoder * decoder)
} }
// surface still in use, try next // surface still in use, try next
if (status != VASurfaceReady) { if (status != VASurfaceReady) {
Debug(3, "video/vaapi: surface %#010x not ready: %d\n", surface, Debug(4, "video/vaapi: surface %#010x not ready: %d\n", surface,
status); status);
if (!VaapiBuggyVdpau || i < 1) { if (!VaapiBuggyVdpau || i < 1) {
continue; continue;
@ -1625,7 +1627,7 @@ static void VaapiInitSurfaceFlags(VaapiDecoder * decoder)
//FIXME: private hack //FIXME: private hack
//decoder->SurfaceFlagsTable[i] |= 0x00006000; //decoder->SurfaceFlagsTable[i] |= 0x00006000;
break; break;
case VideoDeinterlaceSoftware: default:
break; break;
} }
} }
@ -1693,6 +1695,8 @@ static VaapiDecoder *VaapiNewDecoder(void)
decoder->OutputWidth = VideoWindowWidth; decoder->OutputWidth = VideoWindowWidth;
decoder->OutputHeight = VideoWindowHeight; decoder->OutputHeight = VideoWindowHeight;
// get/put still not working
//decoder->GetPutImage = !VaapiBuggyIntel || VaapiNewIntel;
decoder->GetPutImage = !VaapiBuggyIntel; decoder->GetPutImage = !VaapiBuggyIntel;
VaapiDecoders[VaapiDecoderN++] = decoder; VaapiDecoders[VaapiDecoderN++] = decoder;
@ -2015,6 +2019,9 @@ static int VaapiInit(const char *display_name)
if (strstr(s, "Intel i965")) { if (strstr(s, "Intel i965")) {
VaapiBuggyIntel = 1; VaapiBuggyIntel = 1;
} }
if (strstr(s, "Intel i965 driver - 1.0.16.")) {
VaapiNewIntel = 1;
}
// //
// check if driver makes a copy of the VA surface for display. // check if driver makes a copy of the VA surface for display.
// //
@ -2365,7 +2372,7 @@ static void VaapiPutSurfaceX11(VaapiDecoder * decoder, VASurfaceID surface,
// deinterlace // deinterlace
if (interlaced if (interlaced
&& VideoDeinterlace[decoder->Resolution] != VideoDeinterlaceSoftware && VideoDeinterlace[decoder->Resolution] < VideoDeinterlaceSoftBob
&& VideoDeinterlace[decoder->Resolution] != VideoDeinterlaceWeave) { && VideoDeinterlace[decoder->Resolution] != VideoDeinterlaceWeave) {
if (top_field_first) { if (top_field_first) {
if (field) { if (field) {
@ -3127,6 +3134,38 @@ static void VaapiBlackSurface(VaapiDecoder * decoder)
usleep(1 * 1000); usleep(1 * 1000);
} }
#define noUSE_VECTOR ///< use gcc vector extension
#ifdef USE_VECTOR
typedef int8_t v16qi __attribute__ ((vector_size(16)));
typedef int16_t v4hi __attribute__ ((vector_size(8)));
///
/// ELA Edge-based Line Averaging
/// Low-Complexity Interpolation Method
///
/// abcdefg abcdefg abcdefg abcdefg abcdefg
/// x x x x x
/// hijklmn hijklmn hijklmn hijklmn hijklmn
///
static void FilterLineSpatial(uint8_t * dst, const uint8_t * cur, int width,
int above, int below, int next)
{
int x;
// 8/16 128bit xmm register
for (x = 0; x < width; x += 16) {
v16qi a;
// ignore bound violation
a = *(v16qi *) & cur[above + x];
*(v16qi *) & dst[x] = a;
}
}
#else
/// Return the absolute value of an integer. /// Return the absolute value of an integer.
#define ABS(i) ((i) >= 0 ? (i) : (-(i))) #define ABS(i) ((i) >= 0 ? (i) : (-(i)))
@ -3192,6 +3231,8 @@ static void FilterLineSpatial(uint8_t * dst, const uint8_t * cur, int width,
} }
} }
#endif
/// ///
/// Vaapi spatial deinterlace. /// Vaapi spatial deinterlace.
/// ///
@ -3238,7 +3279,7 @@ static void VaapiSpatial(VaapiDecoder * decoder, VAImage * src, VAImage * dst1,
memset(dst1_base, 0x00, dst1->data_size); memset(dst1_base, 0x00, dst1->data_size);
memset(dst2_base, 0xFF, dst2->data_size); memset(dst2_base, 0xFF, dst2->data_size);
} }
// use tmp copy // use tmp copy FIXME: only for intel needed
tmp = malloc(src->data_size); tmp = malloc(src->data_size);
memcpy(tmp, src_base, src->data_size); memcpy(tmp, src_base, src->data_size);
@ -3265,30 +3306,57 @@ static void VaapiSpatial(VaapiDecoder * decoder, VAImage * src, VAImage * dst1,
y + 1 < (unsigned)src->height ? pitch : -pitch, 1); y + 1 < (unsigned)src->height ? pitch : -pitch, 1);
} }
} }
if (VideoSkipChromaDeinterlace[decoder->Resolution]) {
for (y = 0; y < (unsigned)src->height / 2; y++) { // UV
const uint8_t *cur;
cur = tmp + src->offsets[1] + y * pitch;
// copy to 1st
memcpy(dst1_base + src->offsets[1] + y * pitch, cur, width);
// copy to 2nd
memcpy(dst2_base + src->offsets[1] + y * pitch, cur, width);
}
} else {
for (y = 0; y < (unsigned)src->height / 2; y++) { // UV for (y = 0; y < (unsigned)src->height / 2; y++) { // UV
const uint8_t *cur; const uint8_t *cur;
cur = tmp + src->offsets[1] + y * pitch; cur = tmp + src->offsets[1] + y * pitch;
if (y & 1) { if (y & 1) {
// copy to 2nd // copy to 2nd
memcpy(dst2_base + src->offsets[1] + y * pitch, cur, width); memcpy(dst2_base + src->offsets[1] + y * pitch, cur,
width);
// create 1st // create 1st
FilterLineSpatial(dst1_base + src->offsets[1] + y * pitch, cur, FilterLineSpatial(dst1_base + src->offsets[1] + y * pitch,
width, y ? -pitch : pitch, cur, width, y ? -pitch : pitch,
y + 1 < (unsigned)src->height / 2 ? pitch : -pitch, 2); y + 1 < (unsigned)src->height / 2 ? pitch : -pitch, 2);
} else { } else {
// copy to 1st // copy to 1st
memcpy(dst1_base + src->offsets[1] + y * pitch, cur, width); memcpy(dst1_base + src->offsets[1] + y * pitch, cur,
width);
// create 2nd // create 2nd
FilterLineSpatial(dst2_base + src->offsets[1] + y * pitch, cur, FilterLineSpatial(dst2_base + src->offsets[1] + y * pitch,
width, y ? -pitch : pitch, cur, width, y ? -pitch : pitch,
y + 1 < (unsigned)src->height / 2 ? pitch : -pitch, 2); y + 1 < (unsigned)src->height / 2 ? pitch : -pitch, 2);
} }
} }
} else { }
} else { // YV12 or I420
for (p = 0; p < src->num_planes; ++p) { for (p = 0; p < src->num_planes; ++p) {
pitch = src->pitches[p]; pitch = src->pitches[p];
width = src->width >> (p != 0); width = src->width >> (p != 0);
if (VideoSkipChromaDeinterlace[decoder->Resolution] && p) {
for (y = 0; y < (unsigned)(src->height >> 1); y++) {
const uint8_t *cur;
cur = tmp + src->offsets[p] + y * pitch;
// copy to 1st
memcpy(dst1_base + src->offsets[p] + y * pitch, cur,
width);
// copy to 2nd
memcpy(dst2_base + src->offsets[p] + y * pitch, cur,
width);
}
} else {
for (y = 0; y < (unsigned)(src->height >> (p != 0)); y++) { for (y = 0; y < (unsigned)(src->height >> (p != 0)); y++) {
const uint8_t *cur; const uint8_t *cur;
@ -3298,8 +3366,8 @@ static void VaapiSpatial(VaapiDecoder * decoder, VAImage * src, VAImage * dst1,
memcpy(dst2_base + src->offsets[p] + y * pitch, cur, memcpy(dst2_base + src->offsets[p] + y * pitch, cur,
width); width);
// create 1st // create 1st
FilterLineSpatial(dst1_base + src->offsets[p] + y * pitch, FilterLineSpatial(dst1_base + src->offsets[p] +
cur, width, y ? -pitch : pitch, y * pitch, cur, width, y ? -pitch : pitch,
y + 1 < (unsigned)(src->height >> (p != 0)) y + 1 < (unsigned)(src->height >> (p != 0))
? pitch : -pitch, 1); ? pitch : -pitch, 1);
} else { } else {
@ -3307,14 +3375,15 @@ static void VaapiSpatial(VaapiDecoder * decoder, VAImage * src, VAImage * dst1,
memcpy(dst1_base + src->offsets[p] + y * pitch, cur, memcpy(dst1_base + src->offsets[p] + y * pitch, cur,
width); width);
// create 2nd // create 2nd
FilterLineSpatial(dst2_base + src->offsets[p] + y * pitch, FilterLineSpatial(dst2_base + src->offsets[p] +
cur, width, y ? -pitch : pitch, y * pitch, cur, width, y ? -pitch : pitch,
y + 1 < (unsigned)(src->height >> (p != 0)) y + 1 < (unsigned)(src->height >> (p != 0))
? pitch : -pitch, 1); ? pitch : -pitch, 1);
} }
} }
} }
} }
}
free(tmp); free(tmp);
tick5 = GetMsTicks(); tick5 = GetMsTicks();
@ -3592,6 +3661,27 @@ static void VaapiCpuDerive(VaapiDecoder * decoder, VASurfaceID surface)
VASurfaceID out2; VASurfaceID out2;
tick1 = GetMsTicks(); tick1 = GetMsTicks();
#if 0
// get image test
if (decoder->Image->image_id == VA_INVALID_ID) {
VAImageFormat format[1];
VaapiFindImageFormat(decoder, PIX_FMT_NV12, format);
if (vaCreateImage(VaDisplay, format, decoder->InputWidth,
decoder->InputHeight, decoder->Image) != VA_STATUS_SUCCESS) {
Error(_("video/vaapi: can't create image!\n"));
}
}
if (vaGetImage(decoder->VaDisplay, surface, 0, 0, decoder->InputWidth,
decoder->InputHeight, decoder->Image->image_id)
!= VA_STATUS_SUCCESS) {
Error(_("video/vaapi: can't get source image\n"));
VaapiQueueSurface(decoder, surface, 0);
VaapiQueueSurface(decoder, surface, 0);
return;
}
*image = *decoder->Image;
#else
if ((status = if ((status =
vaDeriveImage(decoder->VaDisplay, surface, vaDeriveImage(decoder->VaDisplay, surface,
image)) != VA_STATUS_SUCCESS) { image)) != VA_STATUS_SUCCESS) {
@ -3600,6 +3690,7 @@ static void VaapiCpuDerive(VaapiDecoder * decoder, VASurfaceID surface)
VaapiQueueSurface(decoder, surface, 0); VaapiQueueSurface(decoder, surface, 0);
return; return;
} }
#endif
tick2 = GetMsTicks(); tick2 = GetMsTicks();
Debug(4, "video/vaapi: %c%c%c%c %dx%d*%d\n", image->format.fourcc, Debug(4, "video/vaapi: %c%c%c%c %dx%d*%d\n", image->format.fourcc,
@ -3629,13 +3720,22 @@ static void VaapiCpuDerive(VaapiDecoder * decoder, VASurfaceID surface)
} }
tick4 = GetMsTicks(); tick4 = GetMsTicks();
//VaapiBob(decoder, image, dest1, dest2); switch (VideoDeinterlace[decoder->Resolution]) {
case VideoDeinterlaceSoftBob:
default:
VaapiBob(decoder, image, dest1, dest2);
break;
case VideoDeinterlaceSoftSpatial:
VaapiSpatial(decoder, image, dest1, dest2); VaapiSpatial(decoder, image, dest1, dest2);
break;
}
tick5 = GetMsTicks(); tick5 = GetMsTicks();
#if 1
if (vaDestroyImage(VaDisplay, image->image_id) != VA_STATUS_SUCCESS) { if (vaDestroyImage(VaDisplay, image->image_id) != VA_STATUS_SUCCESS) {
Error(_("video/vaapi: can't destroy image!\n")); Error(_("video/vaapi: can't destroy image!\n"));
} }
#endif
if (vaDestroyImage(VaDisplay, dest1->image_id) != VA_STATUS_SUCCESS) { if (vaDestroyImage(VaDisplay, dest1->image_id) != VA_STATUS_SUCCESS) {
Error(_("video/vaapi: can't destroy image!\n")); Error(_("video/vaapi: can't destroy image!\n"));
} }
@ -3701,8 +3801,15 @@ static void VaapiCpuPut(VaapiDecoder * decoder, VASurfaceID surface)
// FIXME: handle top_field_first // FIXME: handle top_field_first
//VaapiBob(decoder, img1, img2, img3); switch (VideoDeinterlace[decoder->Resolution]) {
case VideoDeinterlaceSoftBob:
default:
VaapiBob(decoder, img1, img2, img3);
break;
case VideoDeinterlaceSoftSpatial:
VaapiSpatial(decoder, img1, img2, img3); VaapiSpatial(decoder, img1, img2, img3);
break;
}
tick3 = GetMsTicks(); tick3 = GetMsTicks();
// get a free surface and upload the image // get a free surface and upload the image
@ -3714,7 +3821,7 @@ static void VaapiCpuPut(VaapiDecoder * decoder, VASurfaceID surface)
vaPutImage(VaDisplay, out, img2->image_id, 0, 0, img2->width, vaPutImage(VaDisplay, out, img2->image_id, 0, 0, img2->width,
img2->height, 0, 0, img2->width, img2->height, 0, 0, img2->width,
img2->height)) != VA_STATUS_SUCCESS) { img2->height)) != VA_STATUS_SUCCESS) {
Error("video/vaapi: can't put image: %d!\n", status); Error(_("video/vaapi: can't put image: %d!\n"), status);
abort(); abort();
} }
VaapiQueueSurface(decoder, out, 1); VaapiQueueSurface(decoder, out, 1);
@ -3734,7 +3841,7 @@ static void VaapiCpuPut(VaapiDecoder * decoder, VASurfaceID surface)
if (vaPutImage(VaDisplay, out, img3->image_id, 0, 0, img3->width, 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, out, 1); VaapiQueueSurface(decoder, out, 1);
if (0 && vaSyncSurface(decoder->VaDisplay, out) != VA_STATUS_SUCCESS) { if (0 && vaSyncSurface(decoder->VaDisplay, out) != VA_STATUS_SUCCESS) {
@ -3843,8 +3950,8 @@ static void VaapiRenderFrame(VaapiDecoder * decoder,
Debug(4, "video/vaapi: hw render hw surface %#010x\n", surface); Debug(4, "video/vaapi: hw render hw surface %#010x\n", surface);
if (interlaced if (interlaced
&& VideoDeinterlace[decoder->Resolution] == && VideoDeinterlace[decoder->Resolution] >=
VideoDeinterlaceSoftware) { VideoDeinterlaceSoftBob) {
VaapiCpuDeinterlace(decoder, surface); VaapiCpuDeinterlace(decoder, surface);
} else { } else {
VaapiQueueSurface(decoder, surface, 0); VaapiQueueSurface(decoder, surface, 0);
@ -4010,7 +4117,7 @@ static void VaapiAdvanceFrame(void)
// 0 -> 1 // 0 -> 1
// 1 -> 0 + advance // 1 -> 0 + advance
if (VideoDeinterlace[decoder->Resolution] != VideoDeinterlaceSoftware if (VideoDeinterlace[decoder->Resolution] < VideoDeinterlaceSoftBob
&& decoder->Interlaced) { && decoder->Interlaced) {
// FIXME: first frame is never shown // FIXME: first frame is never shown
if (decoder->SurfaceField) { if (decoder->SurfaceField) {
@ -4292,7 +4399,7 @@ static int64_t VaapiGetClock(const VaapiDecoder * decoder)
- decoder->SurfaceField); - decoder->SurfaceField);
} }
return decoder->PTS - 20 * 90 * (atomic_read(&decoder->SurfacesFilled) + return decoder->PTS - 20 * 90 * (atomic_read(&decoder->SurfacesFilled) +
1); 2);
} }
/// ///
@ -6609,10 +6716,12 @@ static void VdpauRenderFrame(VdpauDecoder * decoder,
surface = vrs->surface; surface = vrs->surface;
Debug(4, "video/vdpau: hw render hw surface %#08x\n", surface); Debug(4, "video/vdpau: hw render hw surface %#08x\n", surface);
if (VideoDeinterlace[decoder->Resolution] == VideoDeinterlaceSoftware if (interlaced
&& interlaced) { && VideoDeinterlace[decoder->Resolution] >=
VideoDeinterlaceSoftBob) {
// FIXME: software deinterlace avpicture_deinterlace // FIXME: software deinterlace avpicture_deinterlace
// FIXME: VdpauCpuDeinterlace(decoder, surface); // FIXME: VdpauCpuDeinterlace(decoder, surface);
VdpauQueueSurface(decoder, surface, 0);
} else { } else {
VdpauQueueSurface(decoder, surface, 0); VdpauQueueSurface(decoder, surface, 0);
} }
@ -7247,7 +7356,7 @@ static int64_t VdpauGetClock(const VdpauDecoder * decoder)
- decoder->SurfaceField); - decoder->SurfaceField);
} }
return decoder->PTS - 20 * 90 * (atomic_read(&decoder->SurfacesFilled) + return decoder->PTS - 20 * 90 * (atomic_read(&decoder->SurfacesFilled) +
1); 2);
} }
/// ///