]> git.sesse.net Git - ffmpeg/blob - doc/examples/qsvdec.c
doc/utils: fix typo for min() description
[ffmpeg] / doc / examples / qsvdec.c
1 /*
2  * Copyright (c) 2015 Anton Khirnov
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20  * THE SOFTWARE.
21  */
22
23 /**
24  * @file
25  * Intel QSV-accelerated H.264 decoding example.
26  *
27  * @example qsvdec.c
28  * This example shows how to do QSV-accelerated H.264 decoding with output
29  * frames in the VA-API video surfaces.
30  */
31
32 #include "config.h"
33
34 #include <stdio.h>
35
36 #include <mfx/mfxvideo.h>
37
38 #include <va/va.h>
39 #include <va/va_x11.h>
40 #include <X11/Xlib.h>
41
42 #include "libavformat/avformat.h"
43 #include "libavformat/avio.h"
44
45 #include "libavcodec/avcodec.h"
46 #include "libavcodec/qsv.h"
47
48 #include "libavutil/error.h"
49 #include "libavutil/mem.h"
50
51 typedef struct DecodeContext {
52     mfxSession mfx_session;
53     VADisplay va_dpy;
54
55     VASurfaceID *surfaces;
56     mfxMemId    *surface_ids;
57     int         *surface_used;
58     int       nb_surfaces;
59
60     mfxFrameInfo frame_info;
61 } DecodeContext;
62
63 static mfxStatus frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req,
64                              mfxFrameAllocResponse *resp)
65 {
66     DecodeContext *decode = pthis;
67     int err, i;
68
69     if (decode->surfaces) {
70         fprintf(stderr, "Multiple allocation requests.\n");
71         return MFX_ERR_MEMORY_ALLOC;
72     }
73     if (!(req->Type & MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET)) {
74         fprintf(stderr, "Unsupported surface type: %d\n", req->Type);
75         return MFX_ERR_UNSUPPORTED;
76     }
77     if (req->Info.BitDepthLuma != 8 || req->Info.BitDepthChroma != 8 ||
78         req->Info.Shift || req->Info.FourCC != MFX_FOURCC_NV12 ||
79         req->Info.ChromaFormat != MFX_CHROMAFORMAT_YUV420) {
80         fprintf(stderr, "Unsupported surface properties.\n");
81         return MFX_ERR_UNSUPPORTED;
82     }
83
84     decode->surfaces     = av_malloc_array (req->NumFrameSuggested, sizeof(*decode->surfaces));
85     decode->surface_ids  = av_malloc_array (req->NumFrameSuggested, sizeof(*decode->surface_ids));
86     decode->surface_used = av_mallocz_array(req->NumFrameSuggested, sizeof(*decode->surface_used));
87     if (!decode->surfaces || !decode->surface_ids || !decode->surface_used)
88         goto fail;
89
90     err = vaCreateSurfaces(decode->va_dpy, VA_RT_FORMAT_YUV420,
91                            req->Info.Width, req->Info.Height,
92                            decode->surfaces, req->NumFrameSuggested,
93                            NULL, 0);
94     if (err != VA_STATUS_SUCCESS) {
95         fprintf(stderr, "Error allocating VA surfaces\n");
96         goto fail;
97     }
98     decode->nb_surfaces = req->NumFrameSuggested;
99
100     for (i = 0; i < decode->nb_surfaces; i++)
101         decode->surface_ids[i] = &decode->surfaces[i];
102
103     resp->mids           = decode->surface_ids;
104     resp->NumFrameActual = decode->nb_surfaces;
105
106     decode->frame_info = req->Info;
107
108     return MFX_ERR_NONE;
109 fail:
110     av_freep(&decode->surfaces);
111     av_freep(&decode->surface_ids);
112     av_freep(&decode->surface_used);
113
114     return MFX_ERR_MEMORY_ALLOC;
115 }
116
117 static mfxStatus frame_free(mfxHDL pthis, mfxFrameAllocResponse *resp)
118 {
119     return MFX_ERR_NONE;
120 }
121
122 static mfxStatus frame_lock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
123 {
124     return MFX_ERR_UNSUPPORTED;
125 }
126
127 static mfxStatus frame_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
128 {
129     return MFX_ERR_UNSUPPORTED;
130 }
131
132 static mfxStatus frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl)
133 {
134     *hdl = mid;
135     return MFX_ERR_NONE;
136 }
137
138 static void free_surfaces(DecodeContext *decode)
139 {
140     if (decode->surfaces)
141         vaDestroySurfaces(decode->va_dpy, decode->surfaces, decode->nb_surfaces);
142     av_freep(&decode->surfaces);
143     av_freep(&decode->surface_ids);
144     av_freep(&decode->surface_used);
145     decode->nb_surfaces = 0;
146 }
147
148 static void free_buffer(void *opaque, uint8_t *data)
149 {
150     int *used = opaque;
151     *used = 0;
152     av_freep(&data);
153 }
154
155 static int get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
156 {
157     DecodeContext *decode = avctx->opaque;
158
159     mfxFrameSurface1 *surf;
160     AVBufferRef *surf_buf;
161     int idx;
162
163     for (idx = 0; idx < decode->nb_surfaces; idx++) {
164         if (!decode->surface_used[idx])
165             break;
166     }
167     if (idx == decode->nb_surfaces) {
168         fprintf(stderr, "No free surfaces\n");
169         return AVERROR(ENOMEM);
170     }
171
172     surf = av_mallocz(sizeof(*surf));
173     if (!surf)
174         return AVERROR(ENOMEM);
175     surf_buf = av_buffer_create((uint8_t*)surf, sizeof(*surf), free_buffer,
176                                 &decode->surface_used[idx], AV_BUFFER_FLAG_READONLY);
177     if (!surf_buf) {
178         av_freep(&surf);
179         return AVERROR(ENOMEM);
180     }
181
182     surf->Info       = decode->frame_info;
183     surf->Data.MemId = &decode->surfaces[idx];
184
185     frame->buf[0]  = surf_buf;
186     frame->data[3] = (uint8_t*)surf;
187
188     decode->surface_used[idx] = 1;
189
190     return 0;
191 }
192
193 static int get_format(AVCodecContext *avctx, const enum AVPixelFormat *pix_fmts)
194 {
195     while (*pix_fmts != AV_PIX_FMT_NONE) {
196         if (*pix_fmts == AV_PIX_FMT_QSV) {
197             if (!avctx->hwaccel_context) {
198                 DecodeContext *decode = avctx->opaque;
199                 AVQSVContext *qsv = av_qsv_alloc_context();
200                 if (!qsv)
201                     return AV_PIX_FMT_NONE;
202
203                 qsv->session   = decode->mfx_session;
204                 qsv->iopattern = MFX_IOPATTERN_OUT_VIDEO_MEMORY;
205
206                 avctx->hwaccel_context = qsv;
207             }
208
209             return AV_PIX_FMT_QSV;
210         }
211
212         pix_fmts++;
213     }
214
215     fprintf(stderr, "The QSV pixel format not offered in get_format()\n");
216
217     return AV_PIX_FMT_NONE;
218 }
219
220 static int decode_packet(DecodeContext *decode, AVCodecContext *decoder_ctx,
221                          AVFrame *frame, AVPacket *pkt,
222                          AVIOContext *output_ctx)
223 {
224     int ret = 0;
225     int got_frame = 1;
226
227     while (pkt->size > 0 || (!pkt->data && got_frame)) {
228         ret = avcodec_decode_video2(decoder_ctx, frame, &got_frame, pkt);
229         if (ret < 0) {
230             fprintf(stderr, "Error during decoding\n");
231             return ret;
232         }
233
234         pkt->data += ret;
235         pkt->size -= ret;
236
237         /* A real program would do something useful with the decoded frame here.
238          * We just retrieve the raw data and write it to a file, which is rather
239          * useless but pedagogic. */
240         if (got_frame) {
241             mfxFrameSurface1 *surf = (mfxFrameSurface1*)frame->data[3];
242             VASurfaceID    surface = *(VASurfaceID*)surf->Data.MemId;
243
244             VAImageFormat img_fmt = {
245                 .fourcc         = VA_FOURCC_NV12,
246                 .byte_order     = VA_LSB_FIRST,
247                 .bits_per_pixel = 8,
248                 .depth          = 8,
249             };
250
251             VAImage img;
252
253             VAStatus err;
254             uint8_t *data;
255             int i, j;
256
257             img.buf      = VA_INVALID_ID;
258             img.image_id = VA_INVALID_ID;
259
260             err = vaCreateImage(decode->va_dpy, &img_fmt,
261                                 frame->width, frame->height, &img);
262             if (err != VA_STATUS_SUCCESS) {
263                 fprintf(stderr, "Error creating an image: %s\n",
264                         vaErrorStr(err));
265                 ret = AVERROR_UNKNOWN;
266                 goto fail;
267             }
268
269             err = vaGetImage(decode->va_dpy, surface, 0, 0,
270                              frame->width, frame->height,
271                              img.image_id);
272             if (err != VA_STATUS_SUCCESS) {
273                 fprintf(stderr, "Error getting an image: %s\n",
274                         vaErrorStr(err));
275                 ret = AVERROR_UNKNOWN;
276                 goto fail;
277             }
278
279             err = vaMapBuffer(decode->va_dpy, img.buf, (void**)&data);
280             if (err != VA_STATUS_SUCCESS) {
281                 fprintf(stderr, "Error mapping the image buffer: %s\n",
282                         vaErrorStr(err));
283                 ret = AVERROR_UNKNOWN;
284                 goto fail;
285             }
286
287             for (i = 0; i < img.num_planes; i++)
288                 for (j = 0; j < (img.height >> (i > 0)); j++)
289                     avio_write(output_ctx, data + img.offsets[i] + j * img.pitches[i], img.width);
290
291 fail:
292             if (img.buf != VA_INVALID_ID)
293                 vaUnmapBuffer(decode->va_dpy, img.buf);
294             if (img.image_id != VA_INVALID_ID)
295                 vaDestroyImage(decode->va_dpy, img.image_id);
296             av_frame_unref(frame);
297
298             if (ret < 0)
299                 return ret;
300         }
301     }
302
303     return 0;
304 }
305
306 int main(int argc, char **argv)
307 {
308     AVFormatContext *input_ctx = NULL;
309     AVStream *video_st = NULL;
310     AVCodecContext *decoder_ctx = NULL;
311     const AVCodec *decoder;
312
313     AVPacket pkt = { 0 };
314     AVFrame *frame = NULL;
315
316     DecodeContext decode = { NULL };
317
318     Display *dpy = NULL;
319     int va_ver_major, va_ver_minor;
320
321     mfxIMPL mfx_impl = MFX_IMPL_AUTO_ANY;
322     mfxVersion mfx_ver = { { 1, 1 } };
323
324     mfxFrameAllocator frame_allocator = {
325         .pthis = &decode,
326         .Alloc = frame_alloc,
327         .Lock  = frame_lock,
328         .Unlock = frame_unlock,
329         .GetHDL = frame_get_hdl,
330         .Free   = frame_free,
331     };
332
333     AVIOContext *output_ctx = NULL;
334
335     int ret, i, err;
336
337     av_register_all();
338
339     if (argc < 3) {
340         fprintf(stderr, "Usage: %s <input file> <output file>\n", argv[0]);
341         return 1;
342     }
343
344     /* open the input file */
345     ret = avformat_open_input(&input_ctx, argv[1], NULL, NULL);
346     if (ret < 0) {
347         fprintf(stderr, "Cannot open input file '%s': ", argv[1]);
348         goto finish;
349     }
350
351     /* find the first H.264 video stream */
352     for (i = 0; i < input_ctx->nb_streams; i++) {
353         AVStream *st = input_ctx->streams[i];
354
355         if (st->codec->codec_id == AV_CODEC_ID_H264 && !video_st)
356             video_st = st;
357         else
358             st->discard = AVDISCARD_ALL;
359     }
360     if (!video_st) {
361         fprintf(stderr, "No H.264 video stream in the input file\n");
362         goto finish;
363     }
364
365     /* initialize VA-API */
366     dpy = XOpenDisplay(NULL);
367     if (!dpy) {
368         fprintf(stderr, "Cannot open the X display\n");
369         goto finish;
370     }
371     decode.va_dpy = vaGetDisplay(dpy);
372     if (!decode.va_dpy) {
373         fprintf(stderr, "Cannot open the VA display\n");
374         goto finish;
375     }
376
377     err = vaInitialize(decode.va_dpy, &va_ver_major, &va_ver_minor);
378     if (err != VA_STATUS_SUCCESS) {
379         fprintf(stderr, "Cannot initialize VA: %s\n", vaErrorStr(err));
380         goto finish;
381     }
382     fprintf(stderr, "Initialized VA v%d.%d\n", va_ver_major, va_ver_minor);
383
384     /* initialize an MFX session */
385     err = MFXInit(mfx_impl, &mfx_ver, &decode.mfx_session);
386     if (err != MFX_ERR_NONE) {
387         fprintf(stderr, "Error initializing an MFX session\n");
388         goto finish;
389     }
390
391     MFXVideoCORE_SetHandle(decode.mfx_session, MFX_HANDLE_VA_DISPLAY, decode.va_dpy);
392     MFXVideoCORE_SetFrameAllocator(decode.mfx_session, &frame_allocator);
393
394     /* initialize the decoder */
395     decoder = avcodec_find_decoder_by_name("h264_qsv");
396     if (!decoder) {
397         fprintf(stderr, "The QSV decoder is not present in libavcodec\n");
398         goto finish;
399     }
400
401     decoder_ctx = avcodec_alloc_context3(decoder);
402     if (!decoder_ctx) {
403         ret = AVERROR(ENOMEM);
404         goto finish;
405     }
406     decoder_ctx->codec_id = AV_CODEC_ID_H264;
407     if (video_st->codec->extradata_size) {
408         decoder_ctx->extradata = av_mallocz(video_st->codec->extradata_size +
409                                             AV_INPUT_BUFFER_PADDING_SIZE);
410         if (!decoder_ctx->extradata) {
411             ret = AVERROR(ENOMEM);
412             goto finish;
413         }
414         memcpy(decoder_ctx->extradata, video_st->codec->extradata,
415                video_st->codec->extradata_size);
416         decoder_ctx->extradata_size = video_st->codec->extradata_size;
417     }
418     decoder_ctx->refcounted_frames = 1;
419
420     decoder_ctx->opaque      = &decode;
421     decoder_ctx->get_buffer2 = get_buffer;
422     decoder_ctx->get_format  = get_format;
423
424     ret = avcodec_open2(decoder_ctx, NULL, NULL);
425     if (ret < 0) {
426         fprintf(stderr, "Error opening the decoder: ");
427         goto finish;
428     }
429
430     /* open the output stream */
431     ret = avio_open(&output_ctx, argv[2], AVIO_FLAG_WRITE);
432     if (ret < 0) {
433         fprintf(stderr, "Error opening the output context: ");
434         goto finish;
435     }
436
437     frame = av_frame_alloc();
438     if (!frame) {
439         ret = AVERROR(ENOMEM);
440         goto finish;
441     }
442
443     /* actual decoding */
444     while (ret >= 0) {
445         ret = av_read_frame(input_ctx, &pkt);
446         if (ret < 0)
447             break;
448
449         if (pkt.stream_index == video_st->index)
450             ret = decode_packet(&decode, decoder_ctx, frame, &pkt, output_ctx);
451
452         av_packet_unref(&pkt);
453     }
454
455     /* flush the decoder */
456     pkt.data = NULL;
457     pkt.size = 0;
458     ret = decode_packet(&decode, decoder_ctx, frame, &pkt, output_ctx);
459
460 finish:
461     if (ret < 0) {
462         char buf[1024];
463         av_strerror(ret, buf, sizeof(buf));
464         fprintf(stderr, "%s\n", buf);
465     }
466
467     avformat_close_input(&input_ctx);
468
469     av_frame_free(&frame);
470
471     if (decoder_ctx)
472         av_freep(&decoder_ctx->hwaccel_context);
473     avcodec_free_context(&decoder_ctx);
474
475     free_surfaces(&decode);
476
477     if (decode.mfx_session)
478         MFXClose(decode.mfx_session);
479     if (decode.va_dpy)
480         vaTerminate(decode.va_dpy);
481     if (dpy)
482         XCloseDisplay(dpy);
483
484     avio_close(output_ctx);
485
486     return ret;
487 }