1 /*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 /**
20 * @file
21 * Intel Quick Sync Video VPP base function
22 */
23
30
34
35 #define IS_VIDEO_MEMORY(mode) (mode & (MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET | \
36 MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET))
37 #define IS_OPAQUE_MEMORY(mode) (mode & MFX_MEMTYPE_OPAQUE_FRAME)
38 #define IS_SYSTEM_MEMORY(mode) (mode & MFX_MEMTYPE_SYSTEM_MEMORY)
39 #define MFX_IMPL_VIA_MASK(impl) (0x0f00 & (impl))
40
42
47
48 static const struct {
52 {MFX_IOPATTERN_IN_VIDEO_MEMORY, "input is video memory surface" },
53 {MFX_IOPATTERN_IN_SYSTEM_MEMORY, "input is system memory surface" },
54 {MFX_IOPATTERN_IN_OPAQUE_MEMORY, "input is opaque memory surface" },
55 {MFX_IOPATTERN_OUT_VIDEO_MEMORY, "output is video memory surface" },
56 {MFX_IOPATTERN_OUT_SYSTEM_MEMORY, "output is system memory surface" },
57 {MFX_IOPATTERN_OUT_OPAQUE_MEMORY, "output is opaque memory surface" },
58 };
59
61 const char *extra_string)
62 {
64
68 }
69 }
71 desc =
"unknown iopattern";
72
74 return 0;
75 }
76
77 static const struct {
82 { MFX_ERR_NONE, 0, "success" },
84 { MFX_ERR_NULL_PTR,
AVERROR(EINVAL),
"NULL pointer" },
85 { MFX_ERR_UNSUPPORTED,
AVERROR(ENOSYS),
"unsupported" },
86 { MFX_ERR_MEMORY_ALLOC,
AVERROR(ENOMEM),
"failed to allocate memory" },
87 { MFX_ERR_NOT_ENOUGH_BUFFER,
AVERROR(ENOMEM),
"insufficient input/output buffer" },
88 { MFX_ERR_INVALID_HANDLE,
AVERROR(EINVAL),
"invalid handle" },
89 { MFX_ERR_LOCK_MEMORY,
AVERROR(EIO),
"failed to lock the memory block" },
90 { MFX_ERR_NOT_INITIALIZED,
AVERROR_BUG,
"not initialized" },
91 { MFX_ERR_NOT_FOUND,
AVERROR(ENOSYS),
"specified object was not found" },
92 /* the following 3 errors should always be handled explicitly, so those "mappings"
93 * are for completeness only */
95 { MFX_ERR_MORE_SURFACE,
AVERROR_UNKNOWN,
"expect more surface at output" },
96 { MFX_ERR_MORE_BITSTREAM,
AVERROR_UNKNOWN,
"expect more bitstream at output" },
98 { MFX_ERR_DEVICE_LOST,
AVERROR(EIO),
"device lost" },
99 { MFX_ERR_INCOMPATIBLE_VIDEO_PARAM,
AVERROR(EINVAL),
"incompatible video parameters" },
100 { MFX_ERR_INVALID_VIDEO_PARAM,
AVERROR(EINVAL),
"invalid video parameters" },
101 { MFX_ERR_UNDEFINED_BEHAVIOR,
AVERROR_BUG,
"undefined behavior" },
102 { MFX_ERR_DEVICE_FAILED,
AVERROR(EIO),
"device failed" },
103 { MFX_ERR_INCOMPATIBLE_AUDIO_PARAM,
AVERROR(EINVAL),
"incompatible audio parameters" },
104 { MFX_ERR_INVALID_AUDIO_PARAM,
AVERROR(EINVAL),
"invalid audio parameters" },
105
106 { MFX_WRN_IN_EXECUTION, 0, "operation in execution" },
107 { MFX_WRN_DEVICE_BUSY, 0, "device busy" },
108 { MFX_WRN_VIDEO_PARAM_CHANGED, 0, "video parameters changed" },
109 { MFX_WRN_PARTIAL_ACCELERATION, 0, "partial acceleration" },
110 { MFX_WRN_INCOMPATIBLE_VIDEO_PARAM, 0, "incompatible video parameters" },
111 { MFX_WRN_VALUE_NOT_CHANGED, 0, "value is saturated" },
112 { MFX_WRN_OUT_OF_RANGE, 0, "value out of range" },
113 { MFX_WRN_FILTER_SKIPPED, 0, "filter skipped" },
114 { MFX_WRN_INCOMPATIBLE_AUDIO_PARAM, 0, "incompatible audio parameters" },
115 };
116
118 {
125 }
126 }
128 *
desc =
"unknown error";
130 }
131
133 const char *error_string)
134 {
140 }
141
143 const char *warning_string)
144 {
150 }
151
152 /* functions for frameAlloc */
153 static mfxStatus
frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req,
154 mfxFrameAllocResponse *resp)
155 {
158
159 if (!(req->Type & MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET) ||
160 !(req->Type & (MFX_MEMTYPE_FROM_VPPIN | MFX_MEMTYPE_FROM_VPPOUT)) ||
161 !(req->Type & MFX_MEMTYPE_EXTERNAL_FRAME))
162 return MFX_ERR_UNSUPPORTED;
163
164 if (req->Type & MFX_MEMTYPE_FROM_VPPIN) {
165 resp->mids =
av_mallocz(
s->nb_surface_ptrs_in *
sizeof(*resp->mids));
166 if (!resp->mids)
168
169 for (
i = 0;
i <
s->nb_surface_ptrs_in;
i++)
170 resp->mids[
i] =
s->surface_ptrs_in[
i]->Data.MemId;
171
172 resp->NumFrameActual =
s->nb_surface_ptrs_in;
173 } else {
174 resp->mids =
av_mallocz(
s->nb_surface_ptrs_out *
sizeof(*resp->mids));
175 if (!resp->mids)
177
178 for (
i = 0;
i <
s->nb_surface_ptrs_out;
i++)
179 resp->mids[
i] =
s->surface_ptrs_out[
i]->Data.MemId;
180
181 resp->NumFrameActual =
s->nb_surface_ptrs_out;
182 }
183
184 return MFX_ERR_NONE;
185 }
186
187 static mfxStatus
frame_free(mfxHDL pthis, mfxFrameAllocResponse *resp)
188 {
190 return MFX_ERR_NONE;
191 }
192
193 static mfxStatus
frame_lock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
194 {
195 return MFX_ERR_UNSUPPORTED;
196 }
197
198 static mfxStatus
frame_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
199 {
200 return MFX_ERR_UNSUPPORTED;
201 }
202
204 {
205 mfxHDLPair *pair_dst = (mfxHDLPair*)hdl;
206 mfxHDLPair *pair_src = (mfxHDLPair*)mid;
207
208 pair_dst->first = pair_src->first;
209
210 if (pair_src->second != (mfxMemId)MFX_INFINITE)
211 pair_dst->second = pair_src->second;
212 return MFX_ERR_NONE;
213 }
214
216 {
219 return MFX_FOURCC_YV12;
221 return MFX_FOURCC_NV12;
223 return MFX_FOURCC_YUY2;
225 return MFX_FOURCC_RGB4;
226 }
227
228 return MFX_FOURCC_NV12;
229 }
230
232 {
233 switch (
frame->format) {
236 surface->Data.Y =
frame->data[0];
237 surface->Data.UV =
frame->data[1];
238 break;
240 surface->Data.Y =
frame->data[0];
241 surface->Data.U =
frame->data[1];
242 surface->Data.V =
frame->data[2];
243 break;
245 surface->Data.Y =
frame->data[0];
246 surface->Data.U =
frame->data[0] + 1;
247 surface->Data.V =
frame->data[0] + 3;
248 break;
250 surface->Data.B =
frame->data[0];
251 surface->Data.G =
frame->data[0] + 1;
252 surface->Data.R =
frame->data[0] + 2;
253 surface->Data.A =
frame->data[0] + 3;
254 break;
255 default:
256 return MFX_ERR_UNSUPPORTED;
257 }
258 surface->Data.Pitch =
frame->linesize[0];
259
260 return 0;
261 }
262
263 /* fill the surface info */
265 {
270
274
276 frames_hwctx = frames_ctx->
hwctx;
277 *frameinfo = frames_hwctx->
surfaces[0].Info;
278 } else {
283
284 frameinfo->CropX = 0;
285 frameinfo->CropY = 0;
288 frameinfo->PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
290 frameinfo->BitDepthLuma =
desc->comp[0].depth;
291 frameinfo->BitDepthChroma =
desc->comp[0].depth;
292 frameinfo->Shift =
desc->comp[0].depth > 8;
293 if (
desc->log2_chroma_w &&
desc->log2_chroma_h)
294 frameinfo->ChromaFormat = MFX_CHROMAFORMAT_YUV420;
295 else if (
desc->log2_chroma_w)
296 frameinfo->ChromaFormat = MFX_CHROMAFORMAT_YUV422;
297 else
298 frameinfo->ChromaFormat = MFX_CHROMAFORMAT_YUV444;
299 }
300
301 frameinfo->CropW =
link->w;
302 frameinfo->CropH =
link->h;
303 frameinfo->FrameRateExtN =
link->frame_rate.num;
304 frameinfo->FrameRateExtD =
link->frame_rate.den;
307
308 return 0;
309 }
310
312 {
314 /* list->queued==1 means the frame is not cached in VPP
315 * process any more, it can be released to pool. */
316 if ((
list->queued == 1) && !
list->surface.Data.Locked) {
319 }
321 }
322 }
323
325 {
328
330 *
list = (*list)->next;
333 }
334 }
335
337 {
339
343 break;
344 }
345 }
346
352 }
356 }
357
359 }
360
361 /* get the input surface */
363 {
366
368
370 if (!qsv_frame)
372
373 /* Turn AVFrame into mfxFrameSurface1.
374 * For video/opaque memory mode, pix_fmt is AV_PIX_FMT_QSV, and
375 * mfxFrameSurface1 is stored in AVFrame->data[3];
376 * for system memory mode, raw video data is stored in
377 * AVFrame, we should map it into mfxFrameSurface1.
378 */
383 }
386 } else {
387 /* make a copy if the input is not padded as libmfx requires */
392 if (!qsv_frame->
frame)
394
397
401 }
402
404 } else
406
411 }
412 }
413
417
418 qsv_frame->
surface.Info.PicStruct =
421 MFX_PICSTRUCT_FIELD_BFF);
423 qsv_frame->
surface.Info.PicStruct |= MFX_PICSTRUCT_FIELD_REPEATED;
425 qsv_frame->
surface.Info.PicStruct |= MFX_PICSTRUCT_FRAME_DOUBLING;
427 qsv_frame->
surface.Info.PicStruct |= MFX_PICSTRUCT_FRAME_TRIPLING;
428
429 return qsv_frame;
430 }
431
432 /* get the output surface */
434 {
438
440
442 if (!out_frame)
444
445 /* For video memory, get a hw frame;
446 * For system memory, get a sw frame and map it into a mfx_surface. */
449 if (!out_frame->
frame)
451
456 }
457
459 } else {
460 /* Get a frame with aligned dimensions.
461 * Libmfx need system memory being 128x64 aligned */
465 if (!out_frame->
frame)
467
470
475 }
476
477 out_frame->
surface.Info =
s->vpp_param.vpp.Out;
478
479 return out_frame;
480 }
481
482 /* create the QSV session */
484 {
489
493 mfxHDL handle;
494 mfxHandleType handle_type;
495 mfxVersion ver;
496 mfxIMPL impl;
498
499 if (
inlink->hw_frames_ctx) {
501
503 in_frames_hwctx = frames_ctx->
hwctx;
504
506
508 sizeof(*
s->surface_ptrs_in));
509 if (!
s->surface_ptrs_in)
511
513 s->surface_ptrs_in[
i] = in_frames_hwctx->
surfaces +
i;
514
518 s->in_mem_mode = MFX_MEMTYPE_SYSTEM_MEMORY;
519 } else {
522 }
523
525 device_hwctx = device_ctx->
hwctx;
526
530 if (!out_frames_ref)
532
534 MFX_MEMTYPE_OPAQUE_FRAME :
535 MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET | MFX_MEMTYPE_FROM_VPPOUT;
536
538 out_frames_hwctx = out_frames_ctx->
hwctx;
539
548
554 }
555
557 sizeof(*
s->surface_ptrs_out));
558 if (!
s->surface_ptrs_out) {
561 }
562
564 s->surface_ptrs_out[
i] = out_frames_hwctx->
surfaces +
i;
566
569 } else
570 s->out_mem_mode = MFX_MEMTYPE_SYSTEM_MEMORY;
571
572 /* extract the properties of the "master" session given to us */
573 ret = MFXQueryIMPL(device_hwctx->
session, &impl);
574 if (
ret == MFX_ERR_NONE)
575 ret = MFXQueryVersion(device_hwctx->
session, &ver);
576 if (
ret != MFX_ERR_NONE) {
579 }
580
582 handle_type = MFX_HANDLE_VA_DISPLAY;
584 handle_type = MFX_HANDLE_D3D11_DEVICE;
586 handle_type = MFX_HANDLE_D3D9_DEVICE_MANAGER;
587 } else {
590 }
591
592 ret = MFXVideoCORE_GetHandle(device_hwctx->
session, handle_type, &handle);
598 }
599
600 /* create a "slave" session with those same properties, to be used for vpp */
601 ret = MFXInit(impl, &ver, &
s->session);
607 }
608
609 if (handle) {
610 ret = MFXVideoCORE_SetHandle(
s->session, handle_type, handle);
611 if (
ret != MFX_ERR_NONE)
613 }
614
616 ret = MFXJoinSession(device_hwctx->
session,
s->session);
617 if (
ret != MFX_ERR_NONE)
619 }
620
622 s->opaque_alloc.In.Surfaces =
s->surface_ptrs_in;
623 s->opaque_alloc.In.NumSurface =
s->nb_surface_ptrs_in;
624 s->opaque_alloc.In.Type =
s->in_mem_mode;
625
626 s->opaque_alloc.Out.Surfaces =
s->surface_ptrs_out;
627 s->opaque_alloc.Out.NumSurface =
s->nb_surface_ptrs_out;
628 s->opaque_alloc.Out.Type =
s->out_mem_mode;
629
630 s->opaque_alloc.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION;
631 s->opaque_alloc.Header.BufferSz =
sizeof(
s->opaque_alloc);
633 mfxFrameAllocator frame_allocator = {
640 };
641
642 ret = MFXVideoCORE_SetFrameAllocator(
s->session, &frame_allocator);
643 if (
ret != MFX_ERR_NONE)
645 }
646
647 return 0;
648 }
649
651 {
655
659
661 if (!
s->filter_frame)
664
665 /* create the vpp session */
668 goto failed;
669
671 if (!
s->frame_infos) {
673 goto failed;
674 }
675
676 /* Init each input's information */
680 goto failed;
681 }
682
683 /* Update input's frame info according to crop */
688 goto failed;
689 }
690 s->frame_infos[crop->
in_idx].CropX = crop->
x;
691 s->frame_infos[crop->
in_idx].CropY = crop->
y;
692 s->frame_infos[crop->
in_idx].CropW = crop->
w;
693 s->frame_infos[crop->
in_idx].CropH = crop->
h;
694 }
695
696 s->vpp_param.vpp.In =
s->frame_infos[0];
697
701 goto failed;
702 }
703
706 s->ext_buffers =
av_calloc(
s->nb_ext_buffers,
sizeof(*
s->ext_buffers));
707 if (!
s->ext_buffers) {
709 goto failed;
710 }
711
712 s->ext_buffers[0] = (mfxExtBuffer *)&
s->opaque_alloc;
715 s->vpp_param.ExtParam =
s->ext_buffers;
716 s->vpp_param.NumExtParam =
s->nb_ext_buffers;
717 } else {
719 s->vpp_param.ExtParam = param->
ext_buf;
720 }
721
723
724 /** keep fifo size at least 1. Even when async_depth is 0, fifo is used. */
727 if (!
s->async_fifo) {
729 goto failed;
730 }
731
733
735 s->vpp_param.IOPattern |= MFX_IOPATTERN_IN_SYSTEM_MEMORY;
737 s->vpp_param.IOPattern |= MFX_IOPATTERN_IN_VIDEO_MEMORY;
739 s->vpp_param.IOPattern |= MFX_IOPATTERN_IN_OPAQUE_MEMORY;
740
742 s->vpp_param.IOPattern |= MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
744 s->vpp_param.IOPattern |= MFX_IOPATTERN_OUT_VIDEO_MEMORY;
746 s->vpp_param.IOPattern |= MFX_IOPATTERN_OUT_OPAQUE_MEMORY;
747
748 /* Print input memory mode */
750 /* Print output memory mode */
752 ret = MFXVideoVPP_Init(
s->session, &
s->vpp_param);
755 goto failed;
758
760 return 0;
761
762 failed:
764
766 }
767
769 {
771
773 return 0;
774
776 MFXVideoVPP_Close(
s->session);
777 MFXClose(
s->session);
778 }
779
780 /* release all the resources */
789
790 return 0;
791 }
792
794 {
798 mfxSyncPoint sync;
801
803 if (MFXVideoCORE_SyncOperation(
s->session, aframe.
sync, 1000) < 0)
805
806 filter_ret =
s->filter_frame(outlink, aframe.
frame->
frame);
807 if (filter_ret < 0) {
809 return filter_ret;
810 }
814 };
815
816 if (!picref)
817 return 0;
818
820 if (!in_frame) {
824 }
825
826 do {
828 if (!out_frame) {
831 }
832
833 do {
834 ret = MFXVideoVPP_RunFrameVPPAsync(
s->session, &in_frame->
surface,
836 if (
ret == MFX_WRN_DEVICE_BUSY)
838 }
while (
ret == MFX_WRN_DEVICE_BUSY);
839
840 if (
ret < 0 &&
ret != MFX_ERR_MORE_SURFACE) {
841 /* Ignore more_data error */
842 if (
ret == MFX_ERR_MORE_DATA)
844 break;
845 }
848
852
855
856 do {
857 ret = MFXVideoCORE_SyncOperation(
s->session, aframe.
sync, 1000);
858 }
while (
ret == MFX_WRN_IN_EXECUTION);
859
860 filter_ret =
s->filter_frame(outlink, aframe.
frame->
frame);
861 if (filter_ret < 0) {
863 return filter_ret;
864 }
865
869 }
870 }
while(
ret == MFX_ERR_MORE_SURFACE);
871
876
877 return 0;
878 }