picture.c 4.03 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/*****************************************************************************
 * picture.c: VDPAU instance management for VLC
 *****************************************************************************
 * Copyright (C) 2013 Rémi Denis-Courmont
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <stdlib.h>
#include <stdio.h>
27
#include <string.h>
28
29
30
31
32
33
34
#include <assert.h>
#include <vlc_common.h>
#include <vlc_picture.h>
#include "vlc_vdpau.h"

#pragma GCC visibility push(default)

35
36
37
38
static_assert(offsetof (vlc_vdp_video_field_t, context) == 0,
              "Cast assumption failure");

static void SurfaceDestroy(struct picture_context_t *ctx)
39
{
40
    vlc_vdp_video_field_t *field = (vlc_vdp_video_field_t *)ctx;
41
    vlc_vdp_video_frame_t *frame = field->frame;
42
43
    VdpStatus err;

44
45
46
47
48
49
50
51
    /* Destroy field-specific infos */
    free(field);

    if (atomic_fetch_sub(&frame->refs, 1) != 1)
        return;

    /* Destroy frame (video surface) */
    err = vdp_video_surface_destroy(frame->vdp, frame->surface);
52
53
    if (err != VDP_STATUS_OK)
        fprintf(stderr, "video surface destruction failure: %s\n",
54
55
56
                vdp_get_error_string(frame->vdp, err));
    vdp_release_x11(frame->vdp);
    free(frame);
57
58
}

59
static picture_context_t *SurfaceCopy(picture_context_t *ctx)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
60
{
61
    vlc_vdp_video_field_t *fold = (vlc_vdp_video_field_t *)ctx;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
62
63
64
65
66
67
    vlc_vdp_video_frame_t *frame = fold->frame;
    vlc_vdp_video_field_t *fnew = malloc(sizeof (*fnew));
    if (unlikely(fnew == NULL))
        return NULL;

    fnew->context.destroy = SurfaceDestroy;
68
    fnew->context.copy = SurfaceCopy;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
69
70
71
72
73
74
    fnew->frame = frame;
    fnew->structure = fold->structure;
    fnew->procamp = fold->procamp;
    fnew->sharpen = fold->sharpen;

    atomic_fetch_add(&frame->refs, 1);
75
    return &fnew->context;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
76
77
}

78
79
80
81
82
83
84
85
86
static const VdpProcamp procamp_default =
{
    .struct_version = VDP_PROCAMP_VERSION,
    .brightness = 0.f,
    .contrast = 1.f,
    .saturation = 1.f,
    .hue = 0.f,
};

87
88
vlc_vdp_video_field_t *vlc_vdp_video_create(vdp_t *vdp,
                                            VdpVideoSurface surface)
89
{
90
91
92
93
    vlc_vdp_video_field_t *field = malloc(sizeof (*field));
    vlc_vdp_video_frame_t *frame = malloc(sizeof (*frame));

    if (unlikely(field == NULL || frame == NULL))
94
    {
95
96
        free(frame);
        free(field);
97
        return NULL;
98
99
    }

100
    field->context.destroy = SurfaceDestroy;
101
    field->context.copy = SurfaceCopy;
102
    field->frame = frame;
103
    field->structure = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
104
    field->procamp = procamp_default;
105
    field->sharpen = 0.f;
106
107
108
109

    atomic_init(&frame->refs, 1);
    frame->surface = surface;
    frame->vdp = vdp_hold_x11(vdp, &frame->device);
110
111
112
113
114
115
116
117
118
119
120
    return field;
}

VdpStatus vlc_vdp_video_attach(vdp_t *vdp, VdpVideoSurface surface,
                               picture_t *pic)
{
    vlc_vdp_video_field_t *field = vlc_vdp_video_create(vdp, surface);
    if (unlikely(field == NULL))
        return VDP_STATUS_RESOURCES;

    assert(pic->format.i_chroma == VLC_CODEC_VDPAU_VIDEO_420
121
122
        || pic->format.i_chroma == VLC_CODEC_VDPAU_VIDEO_422
        || pic->format.i_chroma == VLC_CODEC_VDPAU_VIDEO_444);
123
124
    assert(!picture_IsReferenced(pic));
    assert(pic->context == NULL);
125
    pic->context = &field->context;
126
127
    return VDP_STATUS_OK;
}