Skip to content

Commit

Permalink
Add initial deinterlacer support
Browse files Browse the repository at this point in the history
Only Bob deinterlacer is working atm.
  • Loading branch information
rellla committed Mar 10, 2015
1 parent 10905b2 commit 1f5b488
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 66 deletions.
4 changes: 4 additions & 0 deletions README
Expand Up @@ -18,6 +18,10 @@ To disable OSD support for e.g. subtitles, set VDPAU_NOOSD environment
variable to 1 (OSD enabled by default):
$ export VDPAU_NOOSD=1

To enable deinterlacer support, set VDPAU_DEINT environment
variable to 1:
$ export VDPAU_DEINT=1

and then for mplayer:
$ mplayer -vo vdpau -vc ffmpeg12vdpau,ffh264vdpau, [filename]
or for mpv:
Expand Down
9 changes: 9 additions & 0 deletions device.c
Expand Up @@ -59,6 +59,15 @@ VdpStatus vdp_imp_device_create_x11(Display *display,
VDPAU_DBG("Failed to open /dev/g2d! OSD disabled.");
}

char *env_vdpau_deint = getenv("VDPAU_DEINT");
if (env_vdpau_deint && strncmp(env_vdpau_deint, "1", 1) == 0)
{
dev->deint_enabled = 1;
VDPAU_DBG("Deinterlacer enabled.");
}
else
VDPAU_DBG("Deinterlacer disabled.");

*get_proc_address = &vdp_get_proc_address;

return VDP_STATUS_OK;
Expand Down
175 changes: 120 additions & 55 deletions presentation_queue.c
Expand Up @@ -122,66 +122,130 @@ static VdpStatus do_presentation_queue_display(task_t *task)

if (os->vs)
{
// VIDEO layer
__disp_layer_info_t layer_info;
memset(&layer_info, 0, sizeof(layer_info));
layer_info.pipe = q->device->osd_enabled ? 0 : 1;
layer_info.mode = DISP_LAYER_WORK_MODE_SCALER;
layer_info.fb.format = DISP_FORMAT_YUV420;
layer_info.fb.seq = DISP_SEQ_UVUV;
switch (os->vs->source_format) {
case VDP_YCBCR_FORMAT_YUYV:
layer_info.fb.mode = DISP_MOD_INTERLEAVED;
layer_info.fb.format = DISP_FORMAT_YUV422;
layer_info.fb.seq = DISP_SEQ_YUYV;
break;
case VDP_YCBCR_FORMAT_UYVY:
layer_info.fb.mode = DISP_MOD_INTERLEAVED;
layer_info.fb.format = DISP_FORMAT_YUV422;
layer_info.fb.seq = DISP_SEQ_UYVY;
break;
case VDP_YCBCR_FORMAT_NV12:
layer_info.fb.mode = DISP_MOD_NON_MB_UV_COMBINED;
break;
case VDP_YCBCR_FORMAT_YV12:
layer_info.fb.mode = DISP_MOD_NON_MB_PLANAR;
break;
default:
case INTERNAL_YCBCR_FORMAT:
layer_info.fb.mode = DISP_MOD_MB_UV_COMBINED;
break;
}
layer_info.fb.br_swap = 0;
layer_info.fb.addr[0] = ve_virt2phys(os->yuv->data) + 0x40000000;
layer_info.fb.addr[1] = ve_virt2phys(os->yuv->data + os->vs->luma_size) + 0x40000000;
layer_info.fb.addr[2] = ve_virt2phys(os->yuv->data + os->vs->luma_size + os->vs->luma_size / 4) + 0x40000000;
static int last_id;

layer_info.fb.cs_mode = DISP_BT601;
layer_info.fb.size.width = os->vs->width;
layer_info.fb.size.height = os->vs->height;
layer_info.src_win.x = os->video_src_rect.x0;
layer_info.src_win.y = os->video_src_rect.y0;
layer_info.src_win.width = os->video_src_rect.x1 - os->video_src_rect.x0;
layer_info.src_win.height = os->video_src_rect.y1 - os->video_src_rect.y0;
layer_info.scn_win.x = x + os->video_dst_rect.x0;
layer_info.scn_win.y = y + os->video_dst_rect.y0;
layer_info.scn_win.width = os->video_dst_rect.x1 - os->video_dst_rect.x0;
layer_info.scn_win.height = os->video_dst_rect.y1 - os->video_dst_rect.y0;
layer_info.ck_enable = q->device->osd_enabled ? 0 : 1;

if (layer_info.scn_win.y < 0)
uint32_t args[4] = { 0, q->target->layer, 0, 0 };

if (os->start_flag == 1)
{
int cutoff = -(layer_info.scn_win.y);
layer_info.src_win.y += cutoff;
layer_info.src_win.height -= cutoff;
layer_info.scn_win.y = 0;
layer_info.scn_win.height -= cutoff;
last_id = -1; // reset the video.id

// VIDEO layer
__disp_layer_info_t layer_info;
memset(&layer_info, 0, sizeof(layer_info));

args[2] = (unsigned long)(&layer_info);
ioctl(q->target->fd, DISP_CMD_LAYER_GET_PARA, args);

layer_info.pipe = q->device->osd_enabled ? 0 : 1;
layer_info.mode = DISP_LAYER_WORK_MODE_SCALER;
layer_info.fb.format = DISP_FORMAT_YUV420;
layer_info.fb.seq = DISP_SEQ_UVUV;
switch (os->vs->source_format) {
case VDP_YCBCR_FORMAT_YUYV:
layer_info.fb.mode = DISP_MOD_INTERLEAVED;
layer_info.fb.format = DISP_FORMAT_YUV422;
layer_info.fb.seq = DISP_SEQ_YUYV;
break;
case VDP_YCBCR_FORMAT_UYVY:
layer_info.fb.mode = DISP_MOD_INTERLEAVED;
layer_info.fb.format = DISP_FORMAT_YUV422;
layer_info.fb.seq = DISP_SEQ_UYVY;
break;
case VDP_YCBCR_FORMAT_NV12:
layer_info.fb.mode = DISP_MOD_NON_MB_UV_COMBINED;
break;
case VDP_YCBCR_FORMAT_YV12:
layer_info.fb.mode = DISP_MOD_NON_MB_PLANAR;
break;
default:
case INTERNAL_YCBCR_FORMAT:
layer_info.fb.mode = DISP_MOD_MB_UV_COMBINED;
break;
}

layer_info.fb.br_swap = 0;
if (os->vs->height < 720)
layer_info.fb.cs_mode = DISP_BT601;
else
layer_info.fb.cs_mode = DISP_BT709;
layer_info.fb.size.width = os->vs->width;
layer_info.fb.size.height = os->vs->height;
layer_info.src_win.x = os->video_src_rect.x0;
layer_info.src_win.y = os->video_src_rect.y0;
layer_info.src_win.width = os->video_src_rect.x1 - os->video_src_rect.x0;
layer_info.src_win.height = os->video_src_rect.y1 - os->video_src_rect.y0;
layer_info.scn_win.x = x + os->video_dst_rect.x0;
layer_info.scn_win.y = y + os->video_dst_rect.y0;
layer_info.scn_win.width = os->video_dst_rect.x1 - os->video_dst_rect.x0;
layer_info.scn_win.height = os->video_dst_rect.y1 - os->video_dst_rect.y0;
layer_info.ck_enable = q->device->osd_enabled ? 0 : 1;

if (layer_info.scn_win.y < 0)
{
int cutoff = -(layer_info.scn_win.y);
layer_info.src_win.y += cutoff;
layer_info.src_win.height -= cutoff;
layer_info.scn_win.y = 0;
layer_info.scn_win.height -= cutoff;
}

layer_info.fb.addr[0] = 0;
layer_info.fb.addr[1] = 0;
layer_info.fb.addr[2] = 0;

args[2] = (unsigned long)(&layer_info);
ioctl(q->target->fd, DISP_CMD_LAYER_SET_PARA, args);

layer_info.fb.addr[0] = ve_virt2phys(os->yuv->data) + 0x40000000;
layer_info.fb.addr[1] = ve_virt2phys(os->yuv->data + os->vs->luma_size) + 0x40000000;
layer_info.fb.addr[2] = ve_virt2phys(os->yuv->data + os->vs->luma_size + os->vs->luma_size / 4) + 0x40000000;

args[2] = (unsigned long)(&layer_info);
ioctl(q->target->fd, DISP_CMD_LAYER_SET_PARA, args);

args[2] = 0;
ioctl(q->target->fd, DISP_CMD_LAYER_OPEN, args);
ioctl(q->target->fd, DISP_CMD_VIDEO_START, args);

os->start_flag = 0; // initial run is done, only set video.addr[] in the next runs
}
else
{
__disp_video_fb_t video;
memset(&video, 0, sizeof(__disp_video_fb_t));
video.id = last_id + 1;
video.addr[0] = ve_virt2phys(os->yuv->data) + 0x40000000;
video.addr[1] = ve_virt2phys(os->yuv->data + os->vs->luma_size) + 0x40000000;
video.addr[2] = ve_virt2phys(os->yuv->data + os->vs->luma_size + os->vs->luma_size / 4) + 0x40000000;

if (q->device->deint_enabled)
{
video.interlace = os->video_deinterlace;
video.top_field_first = os->video_field ? 0 : 1;
}

uint32_t args[4] = { 0, q->target->layer, (unsigned long)(&layer_info), 0 };
ioctl(q->target->fd, DISP_CMD_LAYER_SET_PARA, args);
args[2] = (unsigned long)(&video);
int tmp, i = 0;
while ((tmp = ioctl(q->target->fd, DISP_CMD_VIDEO_GET_FRAME_ID, args)) != last_id)
{
if (tmp == -1)
break;
VDPAU_DBG("Waiting for frame id ... tmp=%d, last_id=%d", tmp, last_id);

usleep(1000);
if (i++ > 10)
{
VDPAU_DBG("Waiting for frame id failed");
break;
}
}

ioctl(q->target->fd, DISP_CMD_VIDEO_SET_FB, args);

last_id++;
}

ioctl(q->target->fd, DISP_CMD_LAYER_OPEN, args);
// Note: might be more reliable (but slower and problematic when there
// are driver issues and the GET functions return wrong values) to query the
// old values instead of relying on our internal csc_change.
Expand Down Expand Up @@ -387,6 +451,7 @@ VdpStatus vdp_presentation_queue_target_destroy(VdpPresentationQueueTarget prese

uint32_t args[4] = { 0, qt->layer, 0, 0 };

ioctl(qt->fd, DISP_CMD_VIDEO_STOP, args);
ioctl(qt->fd, DISP_CMD_LAYER_CLOSE, args);
ioctl(qt->fd, DISP_CMD_LAYER_RELEASE, args);

Expand Down
5 changes: 5 additions & 0 deletions vdpau_private.h
Expand Up @@ -39,6 +39,7 @@ typedef struct
int fd;
int g2d_fd;
int osd_enabled;
int deint_enabled;
} device_ctx_t;

typedef struct
Expand Down Expand Up @@ -94,6 +95,8 @@ typedef struct
float contrast;
float saturation;
float hue;
int deinterlace;
int start_stream;
} mixer_ctx_t;

#define RGBA_FLAG_DIRTY (1 << 0)
Expand Down Expand Up @@ -121,8 +124,10 @@ typedef struct
float contrast;
float saturation;
float hue;
int video_deinterlace, video_field;
VdpTime first_presentation_time;
VdpPresentationQueueStatus status;
int start_flag;
} output_surface_ctx_t;

typedef struct
Expand Down
73 changes: 62 additions & 11 deletions video_mixer.c
Expand Up @@ -41,6 +41,22 @@ VdpStatus vdp_video_mixer_create(VdpDevice device,
mix->device = dev;
mix->contrast = 1.0;
mix->saturation = 1.0;
mix->start_stream = 1;

int i;

if (mix->device->deint_enabled)
{
for (i = 0; i < feature_count; i++)
{
switch (features[i])
{
case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:
mix->deinterlace = 1;
break;
}
}
}

return VDP_STATUS_OK;
}
Expand Down Expand Up @@ -79,12 +95,6 @@ VdpStatus vdp_video_mixer_render(VdpVideoMixer mixer,
if (background_surface != VDP_INVALID_HANDLE)
VDPAU_DBG_ONCE("Requested unimplemented background_surface");


if (current_picture_structure != VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME)
VDPAU_DBG_ONCE("Requested unimplemented picture_structure");



output_surface_ctx_t *os = handle_get(destination_surface);
if (!os)
return VDP_STATUS_INVALID_HANDLE;
Expand All @@ -98,6 +108,12 @@ VdpStatus vdp_video_mixer_render(VdpVideoMixer mixer,

os->yuv = yuv_ref(os->vs->yuv);

if (mix->device->deint_enabled)
{
os->video_deinterlace = (current_picture_structure == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME ? 0 : 1);
os->video_field = current_picture_structure;
}

if (video_source_rect)
{
os->video_src_rect = *video_source_rect;
Expand All @@ -124,15 +140,16 @@ VdpStatus vdp_video_mixer_render(VdpVideoMixer mixer,
os->contrast = mix->contrast;
os->saturation = mix->saturation;
os->hue = mix->hue;
os->start_flag = mix->start_stream;
mix->csc_change = 0;
mix->start_stream = 0;

if (mix->device->osd_enabled && (os->rgba.flags & RGBA_FLAG_DIRTY))
os->rgba.flags |= RGBA_FLAG_NEEDS_CLEAR;

if (layer_count != 0)
VDPAU_DBG_ONCE("Requested unimplemented additional layers");


return VDP_STATUS_OK;
}

Expand All @@ -151,7 +168,6 @@ VdpStatus vdp_video_mixer_get_feature_support(VdpVideoMixer mixer,
if (!mix)
return VDP_STATUS_INVALID_HANDLE;


return VDP_STATUS_ERROR;
}

Expand All @@ -170,6 +186,20 @@ VdpStatus vdp_video_mixer_set_feature_enables(VdpVideoMixer mixer,
if (!mix)
return VDP_STATUS_INVALID_HANDLE;

int i;

if (mix->device->deint_enabled)
{
for (i = 0; i < feature_count; i++)
{
switch (features[i])
{
case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:
mix->deinterlace = feature_enables[i];
break;
}
}
}

return VDP_STATUS_OK;
}
Expand All @@ -186,8 +216,22 @@ VdpStatus vdp_video_mixer_get_feature_enables(VdpVideoMixer mixer,
if (!mix)
return VDP_STATUS_INVALID_HANDLE;

int i;

return VDP_STATUS_ERROR;
if (mix->device->deint_enabled)
{
for (i = 0; i < feature_count; i++)
{
switch (features[i])
{
case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:
feature_enables[i] = mix->deinterlace;
break;
}
}
}

return VDP_STATUS_OK;
}

static void set_csc_matrix(mixer_ctx_t *mix, const VdpCSCMatrix *matrix)
Expand Down Expand Up @@ -242,7 +286,6 @@ VdpStatus vdp_video_mixer_get_parameter_values(VdpVideoMixer mixer,
if (!mix)
return VDP_STATUS_INVALID_HANDLE;


return VDP_STATUS_ERROR;
}

Expand Down Expand Up @@ -273,7 +316,15 @@ VdpStatus vdp_video_mixer_query_feature_support(VdpDevice device,
if (!dev)
return VDP_STATUS_INVALID_HANDLE;

*is_supported = VDP_FALSE;
switch (feature)
{
case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:
*is_supported = VDP_TRUE;
break;
default:
*is_supported = VDP_FALSE;
}

return VDP_STATUS_OK;
}

Expand Down

0 comments on commit 1f5b488

Please sign in to comment.