Browse code

Merge commit '7671dd7cd7d51bbd637cc46d8f104a141bc355ea'

* commit '7671dd7cd7d51bbd637cc46d8f104a141bc355ea':
avconv: add support for VDPAU decoding

Conflicts:
Changelog
Makefile
configure
ffmpeg.h

Merged-by: Michael Niedermayer <michaelni@gmx.at>

Michael Niedermayer authored on 2013/11/23 22:43:08
Showing 7 changed files
... ...
@@ -8,6 +8,7 @@ version <next>
8 8
 - setsar/setdar filters now support variables in ratio expressions
9 9
 - elbg filter
10 10
 - string validation in ffprobe
11
+- support for decoding through VDPAU in ffmpeg (the -hwaccel option)
11 12
 
12 13
 
13 14
 version 2.1:
... ...
@@ -18,7 +18,9 @@ PROGS-$(CONFIG_FFSERVER) += ffserver
18 18
 PROGS      := $(PROGS-yes:%=%$(PROGSSUF)$(EXESUF))
19 19
 INSTPROGS   = $(PROGS-yes:%=%$(PROGSSUF)$(EXESUF))
20 20
 
21
+
21 22
 OBJS-ffmpeg = ffmpeg_opt.o ffmpeg_filter.o
23
+OBJS-ffmpeg-$(HAVE_VDPAU_X11) += ffmpeg_vdpau.o
22 24
 TESTTOOLS   = audiogen videogen rotozoom tiny_psnr tiny_ssim base64
23 25
 HOSTPROGS  := $(TESTTOOLS:%=tests/%) doc/print_options
24 26
 TOOLS       = qt-faststart trasher
... ...
@@ -90,7 +92,7 @@ endef
90 90
 $(foreach D,$(FFLIBS),$(eval $(call DOSUBDIR,lib$(D))))
91 91
 
92 92
 define DOPROG
93
-OBJS-$(1) += $(1).o cmdutils.o $(EXEOBJS)
93
+OBJS-$(1) += $(1).o cmdutils.o $(EXEOBJS) $(OBJS-$(1)-yes)
94 94
 $(1)$(PROGSSUF)_g$(EXESUF): $$(OBJS-$(1))
95 95
 $$(OBJS-$(1)): CFLAGS  += $(CFLAGS-$(1))
96 96
 $(1)$(PROGSSUF)_g$(EXESUF): LDFLAGS += $(LDFLAGS-$(1))
... ...
@@ -1559,11 +1559,13 @@ HAVE_LIST="
1559 1559
     threads
1560 1560
     unistd_h
1561 1561
     usleep
1562
+    vdpau_x11
1562 1563
     vfp_args
1563 1564
     VirtualAlloc
1564 1565
     windows_h
1565 1566
     winsock2_h
1566 1567
     xform_asm
1568
+    xlib
1567 1569
     xmm_clobbers
1568 1570
 "
1569 1571
 
... ...
@@ -4426,10 +4428,12 @@ if enabled libcdio; then
4426 4426
     die "ERROR: libcdio-paranoia not found"
4427 4427
 fi
4428 4428
 
4429
+check_lib X11/Xlib.h XOpenDisplay -lX11 && enable xlib
4430
+
4429 4431
 enabled x11grab                                           &&
4430
-require X11 X11/Xlib.h XOpenDisplay -lX11                 &&
4431 4432
 require Xext X11/extensions/XShm.h XShmCreateImage -lXext &&
4432
-require Xfixes X11/extensions/Xfixes.h XFixesGetCursorImage -lXfixes
4433
+require Xfixes X11/extensions/Xfixes.h XFixesGetCursorImage -lXfixes &&
4434
+{ enabled xlib || die "ERROR: Xlib not found"; }
4433 4435
 
4434 4436
 enabled vaapi &&
4435 4437
     check_lib va/va.h vaInitialize -lva ||
... ...
@@ -4439,6 +4443,10 @@ enabled vdpau &&
4439 4439
     check_cpp_condition vdpau/vdpau.h "defined VDP_DECODER_PROFILE_MPEG4_PART2_ASP" ||
4440 4440
     disable vdpau
4441 4441
 
4442
+enabled vdpau && enabled xlib &&
4443
+    check_lib2 "vdpau/vdpau.h vdpau/vdpau_x11.h" vdp_device_create_x11 -lvdpau &&
4444
+    enable vdpau_x11
4445
+
4442 4446
 # Funny iconv installations are not unusual, so check it after all flags have been set
4443 4447
 disabled iconv || check_func_headers iconv.h iconv || check_lib2 iconv.h iconv -liconv || disable iconv
4444 4448
 
... ...
@@ -631,6 +631,9 @@ Do not use any hardware acceleration (the default).
631 631
 
632 632
 @item auto
633 633
 Automatically select the hardware acceleration method.
634
+
635
+@item vdpau
636
+Use VDPAU (Video Decode and Presentation API for Unix) hardware acceleration.
634 637
 @end table
635 638
 
636 639
 This option has no effect if the selected hwaccel is not available or not
... ...
@@ -648,6 +651,12 @@ Select a device to use for hardware acceleration.
648 648
 This option only makes sense when the @option{-hwaccel} option is also
649 649
 specified. Its exact meaning depends on the specific hardware acceleration
650 650
 method chosen.
651
+
652
+@table @option
653
+@item vdpau
654
+For VDPAU, this option specifies the X11 display/screen to use. If this option
655
+is not specified, the value of the @var{DISPLAY} environment variable is used
656
+@end table
651 657
 @end table
652 658
 
653 659
 @section Audio Options
... ...
@@ -59,6 +59,7 @@
59 59
 enum HWAccelID {
60 60
     HWACCEL_NONE = 0,
61 61
     HWACCEL_AUTO,
62
+    HWACCEL_VDPAU,
62 63
 };
63 64
 
64 65
 typedef struct HWAccel {
... ...
@@ -485,4 +486,6 @@ FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost);
485 485
 
486 486
 int ffmpeg_parse_options(int argc, char **argv);
487 487
 
488
+int vdpau_init(AVCodecContext *s);
489
+
488 490
 #endif /* FFMPEG_H */
... ...
@@ -64,6 +64,9 @@
64 64
 }
65 65
 
66 66
 const HWAccel hwaccels[] = {
67
+#if HAVE_VDPAU_X11
68
+    { "vdpau", vdpau_init, HWACCEL_VDPAU, AV_PIX_FMT_VDPAU },
69
+#endif
67 70
     { 0 },
68 71
 };
69 72
 
70 73
new file mode 100644
... ...
@@ -0,0 +1,335 @@
0
+/*
1
+ * This file is part of FFmpeg.
2
+ *
3
+ * FFmpeg is free software; you can redistribute it and/or
4
+ * modify it under the terms of the GNU Lesser General Public
5
+ * License as published by the Free Software Foundation; either
6
+ * version 2.1 of the License, or (at your option) any later version.
7
+ *
8
+ * FFmpeg is distributed in the hope that it will be useful,
9
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
+ * Lesser General Public License for more details.
12
+ *
13
+ * You should have received a copy of the GNU Lesser General Public
14
+ * License along with FFmpeg; if not, write to the Free Software
15
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+ */
17
+
18
+#include <stdint.h>
19
+
20
+#include <vdpau/vdpau.h>
21
+#include <vdpau/vdpau_x11.h>
22
+
23
+#include <X11/Xlib.h>
24
+
25
+#include "ffmpeg.h"
26
+
27
+#include "libavcodec/vdpau.h"
28
+
29
+#include "libavutil/avassert.h"
30
+#include "libavutil/buffer.h"
31
+#include "libavutil/frame.h"
32
+#include "libavutil/pixfmt.h"
33
+
34
+typedef struct VDPAUContext {
35
+    Display *dpy;
36
+
37
+    VdpDevice  device;
38
+    VdpDecoder decoder;
39
+    VdpGetProcAddress *get_proc_address;
40
+
41
+    VdpGetErrorString                               *get_error_string;
42
+    VdpGetInformationString                         *get_information_string;
43
+    VdpDeviceDestroy                                *device_destroy;
44
+    VdpDecoderCreate                                *decoder_create;
45
+    VdpDecoderDestroy                               *decoder_destroy;
46
+    VdpDecoderRender                                *decoder_render;
47
+    VdpVideoSurfaceCreate                           *video_surface_create;
48
+    VdpVideoSurfaceDestroy                          *video_surface_destroy;
49
+    VdpVideoSurfaceGetBitsYCbCr                     *video_surface_get_bits;
50
+    VdpVideoSurfaceGetParameters                    *video_surface_get_parameters;
51
+    VdpVideoSurfaceQueryGetPutBitsYCbCrCapabilities *video_surface_query;
52
+
53
+    AVFrame *tmp_frame;
54
+
55
+    enum AVPixelFormat pix_fmt;
56
+    VdpYCbCrFormat vdpau_format;
57
+} VDPAUContext;
58
+
59
+static void vdpau_uninit(AVCodecContext *s)
60
+{
61
+    InputStream  *ist = s->opaque;
62
+    VDPAUContext *ctx = ist->hwaccel_ctx;
63
+
64
+    ist->hwaccel_uninit        = NULL;
65
+    ist->hwaccel_get_buffer    = NULL;
66
+    ist->hwaccel_retrieve_data = NULL;
67
+
68
+    if (ctx->decoder_destroy)
69
+        ctx->decoder_destroy(ctx->decoder);
70
+
71
+    if (ctx->device_destroy)
72
+        ctx->device_destroy(ctx->device);
73
+
74
+    if (ctx->dpy)
75
+        XCloseDisplay(ctx->dpy);
76
+
77
+    av_frame_free(&ctx->tmp_frame);
78
+
79
+    av_freep(&ist->hwaccel_ctx);
80
+    av_freep(&s->hwaccel_context);
81
+}
82
+
83
+static void vdpau_release_buffer(void *opaque, uint8_t *data)
84
+{
85
+    VdpVideoSurface surface = *(VdpVideoSurface*)data;
86
+    VDPAUContext *ctx = opaque;
87
+
88
+    ctx->video_surface_destroy(surface);
89
+    av_freep(&data);
90
+}
91
+
92
+static int vdpau_get_buffer(AVCodecContext *s, AVFrame *frame, int flags)
93
+{
94
+    InputStream         *ist = s->opaque;
95
+    VDPAUContext        *ctx = ist->hwaccel_ctx;
96
+    VdpVideoSurface *surface;
97
+    VdpStatus err;
98
+
99
+    av_assert0(frame->format == AV_PIX_FMT_VDPAU);
100
+
101
+    surface = av_malloc(sizeof(*surface));
102
+    if (!surface)
103
+        return AVERROR(ENOMEM);
104
+
105
+    frame->buf[0] = av_buffer_create((uint8_t*)surface, sizeof(*surface),
106
+                                     vdpau_release_buffer, ctx,
107
+                                     AV_BUFFER_FLAG_READONLY);
108
+    if (!frame->buf[0]) {
109
+        av_freep(&surface);
110
+        return AVERROR(ENOMEM);
111
+    }
112
+
113
+    // properly we should keep a pool of surfaces instead of creating
114
+    // them anew for each frame, but since we don't care about speed
115
+    // much in this code, we don't bother
116
+    err = ctx->video_surface_create(ctx->device, VDP_CHROMA_TYPE_420,
117
+                                    frame->width, frame->height, surface);
118
+    if (err != VDP_STATUS_OK) {
119
+        av_log(NULL, AV_LOG_ERROR, "Error allocating a VDPAU video surface: %s\n",
120
+               ctx->get_error_string(err));
121
+        av_buffer_unref(&frame->buf[0]);
122
+        return AVERROR_UNKNOWN;
123
+    }
124
+
125
+    frame->data[3] = (uint8_t*)(uintptr_t)*surface;
126
+
127
+    return 0;
128
+}
129
+
130
+static int vdpau_retrieve_data(AVCodecContext *s, AVFrame *frame)
131
+{
132
+    VdpVideoSurface surface = (VdpVideoSurface)(uintptr_t)frame->data[3];
133
+    InputStream        *ist = s->opaque;
134
+    VDPAUContext       *ctx = ist->hwaccel_ctx;
135
+    VdpStatus err;
136
+    int ret, chroma_type;
137
+
138
+    err = ctx->video_surface_get_parameters(surface, &chroma_type,
139
+                                            &ctx->tmp_frame->width,
140
+                                            &ctx->tmp_frame->height);
141
+    if (err != VDP_STATUS_OK) {
142
+        av_log(NULL, AV_LOG_ERROR, "Error getting surface parameters: %s\n",
143
+               ctx->get_error_string(err));
144
+        return AVERROR_UNKNOWN;
145
+    }
146
+    ctx->tmp_frame->format = ctx->pix_fmt;
147
+
148
+    ret = av_frame_get_buffer(ctx->tmp_frame, 32);
149
+    if (ret < 0)
150
+        return ret;
151
+
152
+    ctx->tmp_frame->width  = frame->width;
153
+    ctx->tmp_frame->height = frame->height;
154
+
155
+    err = ctx->video_surface_get_bits(surface, ctx->vdpau_format,
156
+                                      (void * const *)ctx->tmp_frame->data,
157
+                                      ctx->tmp_frame->linesize);
158
+    if (err != VDP_STATUS_OK) {
159
+        av_log(NULL, AV_LOG_ERROR, "Error retrieving frame data from VDPAU: %s\n",
160
+               ctx->get_error_string(err));
161
+        ret = AVERROR_UNKNOWN;
162
+        goto fail;
163
+    }
164
+
165
+    if (ctx->vdpau_format == VDP_YCBCR_FORMAT_YV12)
166
+        FFSWAP(uint8_t*, ctx->tmp_frame->data[1], ctx->tmp_frame->data[2]);
167
+
168
+    ret = av_frame_copy_props(ctx->tmp_frame, frame);
169
+    if (ret < 0)
170
+        goto fail;
171
+
172
+    av_frame_unref(frame);
173
+    av_frame_move_ref(frame, ctx->tmp_frame);
174
+    return 0;
175
+
176
+fail:
177
+    av_frame_unref(ctx->tmp_frame);
178
+    return ret;
179
+}
180
+
181
+static const int vdpau_formats[][2] = {
182
+    { VDP_YCBCR_FORMAT_YV12, AV_PIX_FMT_YUV420P },
183
+    { VDP_YCBCR_FORMAT_NV12, AV_PIX_FMT_NV12 },
184
+    { VDP_YCBCR_FORMAT_YUYV, AV_PIX_FMT_YUYV422 },
185
+    { VDP_YCBCR_FORMAT_UYVY, AV_PIX_FMT_UYVY422 },
186
+};
187
+
188
+static int vdpau_alloc(AVCodecContext *s)
189
+{
190
+    InputStream  *ist = s->opaque;
191
+    int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR;
192
+    AVVDPAUContext *vdpau_ctx;
193
+    VDPAUContext *ctx;
194
+    const char *display, *vendor;
195
+    VdpStatus err;
196
+    int i;
197
+
198
+    ctx = av_mallocz(sizeof(*ctx));
199
+    if (!ctx)
200
+        return AVERROR(ENOMEM);
201
+
202
+    ist->hwaccel_ctx           = ctx;
203
+    ist->hwaccel_uninit        = vdpau_uninit;
204
+    ist->hwaccel_get_buffer    = vdpau_get_buffer;
205
+    ist->hwaccel_retrieve_data = vdpau_retrieve_data;
206
+
207
+    ctx->tmp_frame = av_frame_alloc();
208
+    if (!ctx->tmp_frame)
209
+        goto fail;
210
+
211
+    ctx->dpy = XOpenDisplay(ist->hwaccel_device);
212
+    if (!ctx->dpy) {
213
+        av_log(NULL, loglevel, "Cannot open the X11 display %s.\n",
214
+               XDisplayName(ist->hwaccel_device));
215
+        goto fail;
216
+    }
217
+    display = XDisplayString(ctx->dpy);
218
+
219
+    err = vdp_device_create_x11(ctx->dpy, XDefaultScreen(ctx->dpy), &ctx->device,
220
+                                &ctx->get_proc_address);
221
+    if (err != VDP_STATUS_OK) {
222
+        av_log(NULL, loglevel, "VDPAU device creation on X11 display %s failed.\n",
223
+               display);
224
+        goto fail;
225
+    }
226
+
227
+#define GET_CALLBACK(id, result)                                                \
228
+do {                                                                            \
229
+    void *tmp;                                                                  \
230
+    err = ctx->get_proc_address(ctx->device, id, &tmp);                         \
231
+    if (err != VDP_STATUS_OK) {                                                 \
232
+        av_log(NULL, loglevel, "Error getting the " #id " callback.\n");        \
233
+        goto fail;                                                              \
234
+    }                                                                           \
235
+    ctx->result = tmp;                                                          \
236
+} while (0)
237
+
238
+    GET_CALLBACK(VDP_FUNC_ID_GET_ERROR_STRING,               get_error_string);
239
+    GET_CALLBACK(VDP_FUNC_ID_GET_INFORMATION_STRING,         get_information_string);
240
+    GET_CALLBACK(VDP_FUNC_ID_DEVICE_DESTROY,                 device_destroy);
241
+    GET_CALLBACK(VDP_FUNC_ID_DECODER_CREATE,                 decoder_create);
242
+    GET_CALLBACK(VDP_FUNC_ID_DECODER_DESTROY,                decoder_destroy);
243
+    GET_CALLBACK(VDP_FUNC_ID_DECODER_RENDER,                 decoder_render);
244
+    GET_CALLBACK(VDP_FUNC_ID_VIDEO_SURFACE_CREATE,           video_surface_create);
245
+    GET_CALLBACK(VDP_FUNC_ID_VIDEO_SURFACE_DESTROY,          video_surface_destroy);
246
+    GET_CALLBACK(VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR, video_surface_get_bits);
247
+    GET_CALLBACK(VDP_FUNC_ID_VIDEO_SURFACE_GET_PARAMETERS,   video_surface_get_parameters);
248
+    GET_CALLBACK(VDP_FUNC_ID_VIDEO_SURFACE_QUERY_GET_PUT_BITS_Y_CB_CR_CAPABILITIES,
249
+                 video_surface_query);
250
+
251
+    for (i = 0; i < FF_ARRAY_ELEMS(vdpau_formats); i++) {
252
+        VdpBool supported;
253
+        err = ctx->video_surface_query(ctx->device, VDP_CHROMA_TYPE_420,
254
+                                       vdpau_formats[i][0], &supported);
255
+        if (err != VDP_STATUS_OK) {
256
+            av_log(NULL, loglevel,
257
+                   "Error querying VDPAU surface capabilities: %s\n",
258
+                   ctx->get_error_string(err));
259
+            goto fail;
260
+        }
261
+        if (supported)
262
+            break;
263
+    }
264
+    if (i == FF_ARRAY_ELEMS(vdpau_formats)) {
265
+        av_log(NULL, loglevel,
266
+               "No supported VDPAU format for retrieving the data.\n");
267
+        return AVERROR(EINVAL);
268
+    }
269
+    ctx->vdpau_format = vdpau_formats[i][0];
270
+    ctx->pix_fmt      = vdpau_formats[i][1];
271
+
272
+    vdpau_ctx = av_vdpau_alloc_context();
273
+    if (!vdpau_ctx)
274
+        goto fail;
275
+    vdpau_ctx->render = ctx->decoder_render;
276
+
277
+    s->hwaccel_context = vdpau_ctx;
278
+
279
+    ctx->get_information_string(&vendor);
280
+    av_log(NULL, AV_LOG_VERBOSE, "Using VDPAU -- %s -- on X11 display %s, "
281
+           "to decode input stream #%d:%d.\n", vendor,
282
+           display, ist->file_index, ist->st->index);
283
+
284
+    return 0;
285
+
286
+fail:
287
+    av_log(NULL, loglevel, "VDPAU init failed for stream #%d:%d.\n",
288
+           ist->file_index, ist->st->index);
289
+    vdpau_uninit(s);
290
+    return AVERROR(EINVAL);
291
+}
292
+
293
+int vdpau_init(AVCodecContext *s)
294
+{
295
+    InputStream *ist = s->opaque;
296
+    int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR;
297
+    AVVDPAUContext *vdpau_ctx;
298
+    VDPAUContext *ctx;
299
+    VdpStatus err;
300
+    int profile, ret;
301
+
302
+    if (!ist->hwaccel_ctx) {
303
+        ret = vdpau_alloc(s);
304
+        if (ret < 0)
305
+            return ret;
306
+    }
307
+    ctx       = ist->hwaccel_ctx;
308
+    vdpau_ctx = s->hwaccel_context;
309
+
310
+    ret = av_vdpau_get_profile(s, &profile);
311
+    if (ret < 0) {
312
+        av_log(NULL, loglevel, "No known VDPAU decoder profile for this stream.\n");
313
+        return AVERROR(EINVAL);
314
+    }
315
+
316
+    if (ctx->decoder)
317
+        ctx->decoder_destroy(ctx->decoder);
318
+
319
+    err = ctx->decoder_create(ctx->device, profile,
320
+                              s->coded_width, s->coded_height,
321
+                              16, &ctx->decoder);
322
+    if (err != VDP_STATUS_OK) {
323
+        av_log(NULL, loglevel, "Error creating the VDPAU decoder: %s\n",
324
+               ctx->get_error_string(err));
325
+        return AVERROR_UNKNOWN;
326
+    }
327
+
328
+    vdpau_ctx->decoder = ctx->decoder;
329
+
330
+    ist->hwaccel_get_buffer    = vdpau_get_buffer;
331
+    ist->hwaccel_retrieve_data = vdpau_retrieve_data;
332
+
333
+    return 0;
334
+}