From 5719b3714349fa92a45fd3002e720537e98698e1 Mon Sep 17 00:00:00 2001 From: "Xu, Zhengguo" Date: Mon, 15 Apr 2024 15:33:12 +0800 Subject: [PATCH] [Decode] Test shared surface copy between two media instances Signed-off-by: Xu, Zhengguo --- decode/Makefile.am | 6 +- decode/meson.build | 3 + decode/mpeg2sharedsurfacecopy.cpp | 348 ++++++++++++++++++++++++++++++ 3 files changed, 356 insertions(+), 1 deletion(-) create mode 100644 decode/mpeg2sharedsurfacecopy.cpp diff --git a/decode/Makefile.am b/decode/Makefile.am index 8ea92522..fe7f7362 100644 --- a/decode/Makefile.am +++ b/decode/Makefile.am @@ -20,7 +20,7 @@ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -bin_PROGRAMS = mpeg2vldemo loadjpeg +bin_PROGRAMS = mpeg2vldemo loadjpeg mpeg2sharedsurfacecopy AM_CPPFLAGS = \ -Wall \ @@ -40,6 +40,10 @@ TEST_LIBS = \ mpeg2vldemo_LDADD = $(TEST_LIBS) mpeg2vldemo_SOURCES = mpeg2vldemo.cpp +mpeg2sharedsurfacecopy_LDADD = $(TEST_LIBS) +mpeg2sharedsurfacecopy_SOURCES = mpeg2sharedsurfacecopy.cpp + + loadjpeg_LDADD = $(TEST_LIBS) loadjpeg_SOURCES = loadjpeg.c tinyjpeg.c diff --git a/decode/meson.build b/decode/meson.build index d0c1d1b0..1737f615 100644 --- a/decode/meson.build +++ b/decode/meson.build @@ -1,6 +1,9 @@ executable('mpeg2vldemo', [ 'mpeg2vldemo.cpp' ], dependencies: libva_display_dep, install: true) +executable('mpeg2sharedsurfacecopy', [ 'mpeg2sharedsurfacecopy.cpp' ], + dependencies: libva_display_dep, + install: true) executable('loadjpeg', [ 'loadjpeg.c', 'tinyjpeg.c' ], dependencies: libva_display_dep, install: true) diff --git a/decode/mpeg2sharedsurfacecopy.cpp b/decode/mpeg2sharedsurfacecopy.cpp new file mode 100644 index 00000000..beba2101 --- /dev/null +++ b/decode/mpeg2sharedsurfacecopy.cpp @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2007-2008 Intel Corporation. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * it is a real program to show how VAAPI decode work, + * It does VLD decode for a simple MPEG2 clip "mpeg2-I.m2v" + * "mpeg2-I.m2v" and VA parameters are hardcoded into mpeg2vldemo.c, + * See mpeg2-I.jif to know how those VA parameters come from + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "va_display.h" +#include +#include + +#define CHECK_VASTATUS(va_status,func) \ +if (va_status != VA_STATUS_SUCCESS) { \ + fprintf(stderr,"%s:%s (%d) failed,exit\n", __func__, func, __LINE__); \ + exit(1); \ +} + + +#define CLIP_WIDTH 1920 +#define CLIP_HEIGHT 1920 + +VADisplay openDriver(char *device_paths) +{ + int drm_fd = open(device_paths, O_RDWR); + if (drm_fd < 0) + { + printf("####INFO: device %s is invalid !\n", device_paths); + return NULL; + } + + VADisplay va_dpy = vaGetDisplayDRM(drm_fd); + if(va_dpy) + return va_dpy; + + close(drm_fd); + drm_fd = -1; + return 0; +} + +/* Data dump of a 16x16 MPEG2 video clip,it has one I frame + */ +static unsigned char mpeg2_clip[] = { + 0x00, 0x00, 0x01, 0xb3, 0x01, 0x00, 0x10, 0x13, 0xff, 0xff, 0xe0, 0x18, 0x00, 0x00, 0x01, 0xb5, + 0x14, 0x8a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0xb8, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x0f, 0xff, 0xf8, 0x00, 0x00, 0x01, 0xb5, 0x8f, 0xff, 0xf3, 0x41, 0x80, 0x00, + 0x00, 0x01, 0x01, 0x13, 0xe1, 0x00, 0x15, 0x81, 0x54, 0xe0, 0x2a, 0x05, 0x43, 0x00, 0x2d, 0x60, + 0x18, 0x01, 0x4e, 0x82, 0xb9, 0x58, 0xb1, 0x83, 0x49, 0xa4, 0xa0, 0x2e, 0x05, 0x80, 0x4b, 0x7a, + 0x00, 0x01, 0x38, 0x20, 0x80, 0xe8, 0x05, 0xff, 0x60, 0x18, 0xe0, 0x1d, 0x80, 0x98, 0x01, 0xf8, + 0x06, 0x00, 0x54, 0x02, 0xc0, 0x18, 0x14, 0x03, 0xb2, 0x92, 0x80, 0xc0, 0x18, 0x94, 0x42, 0x2c, + 0xb2, 0x11, 0x64, 0xa0, 0x12, 0x5e, 0x78, 0x03, 0x3c, 0x01, 0x80, 0x0e, 0x80, 0x18, 0x80, 0x6b, + 0xca, 0x4e, 0x01, 0x0f, 0xe4, 0x32, 0xc9, 0xbf, 0x01, 0x42, 0x69, 0x43, 0x50, 0x4b, 0x01, 0xc9, + 0x45, 0x80, 0x50, 0x01, 0x38, 0x65, 0xe8, 0x01, 0x03, 0xf3, 0xc0, 0x76, 0x00, 0xe0, 0x03, 0x20, + 0x28, 0x18, 0x01, 0xa9, 0x34, 0x04, 0xc5, 0xe0, 0x0b, 0x0b, 0x04, 0x20, 0x06, 0xc0, 0x89, 0xff, + 0x60, 0x12, 0x12, 0x8a, 0x2c, 0x34, 0x11, 0xff, 0xf6, 0xe2, 0x40, 0xc0, 0x30, 0x1b, 0x7a, 0x01, + 0xa9, 0x0d, 0x00, 0xac, 0x64 +}; + +/* hardcoded here without a bitstream parser helper + * please see picture mpeg2-I.jpg for bitstream details + */ +static VAPictureParameterBufferMPEG2 pic_param = { + horizontal_size: 16, + vertical_size: 16, + forward_reference_picture: 0xffffffff, + backward_reference_picture: 0xffffffff, + picture_coding_type: 1, + f_code: 0xffff, + { + { + intra_dc_precision: 0, + picture_structure: 3, + top_field_first: 0, + frame_pred_frame_dct: 1, + concealment_motion_vectors: 0, + q_scale_type: 0, + intra_vlc_format: 0, + alternate_scan: 0, + repeat_first_field: 0, + progressive_frame: 1, + is_first_field: 1 + }, + } +}; + +/* see MPEG2 spec65 for the defines of matrix */ +static VAIQMatrixBufferMPEG2 iq_matrix = { + load_intra_quantiser_matrix: 1, + load_non_intra_quantiser_matrix: 1, + load_chroma_intra_quantiser_matrix: 0, + load_chroma_non_intra_quantiser_matrix: 0, +intra_quantiser_matrix: + { + 8, 16, 16, 19, 16, 19, 22, 22, + 22, 22, 22, 22, 26, 24, 26, 27, + 27, 27, 26, 26, 26, 26, 27, 27, + 27, 29, 29, 29, 34, 34, 34, 29, + 29, 29, 27, 27, 29, 29, 32, 32, + 34, 34, 37, 38, 37, 35, 35, 34, + 35, 38, 38, 40, 40, 40, 48, 48, + 46, 46, 56, 56, 58, 69, 69, 83 + }, +non_intra_quantiser_matrix: + {16}, +chroma_intra_quantiser_matrix: + {0}, +chroma_non_intra_quantiser_matrix: + {0} +}; + +#if 1 +static VASliceParameterBufferMPEG2 slice_param = { + slice_data_size: 150, + slice_data_offset: 0, + slice_data_flag: 0, + macroblock_offset: 38, /* 4byte + 6bits=38bits */ + slice_horizontal_position: 0, + slice_vertical_position: 0, + quantiser_scale_code: 2, + intra_slice_flag: 0 +}; +#endif + +#define CLIP_WIDTH 16 +#define CLIP_HEIGHT 16 + +#define WIN_WIDTH (CLIP_WIDTH<<1) +#define WIN_HEIGHT (CLIP_HEIGHT<<1) + +int main(int argc, char **argv) +{ + VAEntrypoint entrypoints[5]; + int num_entrypoints, vld_entrypoint; + VAConfigAttrib attrib; + VAConfigID config_id; + VASurfaceID surface_id_1, surface_id_2; + VAContextID context_id_1; + VABufferID pic_param_buf, iqmatrix_buf, slice_param_buf, slice_data_buf; + int major_ver, minor_ver; + VADisplay va_dpy_1, va_dpy_2; + VAStatus va_status; + + va_init_display_args(&argc, argv); + va_dpy_1 = openDriver(argv[1]); + va_status = vaInitialize(va_dpy_1, &major_ver, &minor_ver); + assert(va_status == VA_STATUS_SUCCESS); + + va_dpy_2 = openDriver(argv[1]); + va_status = vaInitialize(va_dpy_2, &major_ver, &minor_ver); + assert(va_status == VA_STATUS_SUCCESS); + +////////////////////////////create decode and export surface//////////////////////////////// + va_status = vaQueryConfigEntrypoints(va_dpy_1, VAProfileMPEG2Main, entrypoints, + &num_entrypoints); + CHECK_VASTATUS(va_status, "vaQueryConfigEntrypoints"); + + for (vld_entrypoint = 0; vld_entrypoint < num_entrypoints; vld_entrypoint++) { + if (entrypoints[vld_entrypoint] == VAEntrypointVLD) + break; + } + if (vld_entrypoint == num_entrypoints) { + /* not find VLD entry point */ + assert(0); + } + + /* Assuming finding VLD, find out the format for the render target */ + attrib.type = VAConfigAttribRTFormat; + vaGetConfigAttributes(va_dpy_1, VAProfileMPEG2Main, VAEntrypointVLD, + &attrib, 1); + if ((attrib.value & VA_RT_FORMAT_YUV420) == 0) { + /* not find desired YUV420 RT format */ + assert(0); + } + + va_status = vaCreateConfig(va_dpy_1, VAProfileMPEG2Main, VAEntrypointVLD, + &attrib, 1, &config_id); + CHECK_VASTATUS(va_status, "vaQueryConfigEntrypoints"); + + //create surface1 + va_status = vaCreateSurfaces( + va_dpy_1, + VA_RT_FORMAT_YUV420, CLIP_WIDTH, CLIP_HEIGHT, + &surface_id_1, 1, + NULL, 0 + ); + CHECK_VASTATUS(va_status, "vaCreateSurfaces"); + + /* Create a context1 for this decode pipe */ + va_status = vaCreateContext(va_dpy_1, config_id, + CLIP_WIDTH, + ((CLIP_HEIGHT + 15) / 16) * 16, + VA_PROGRESSIVE, + &surface_id_1, + 1, + &context_id_1); + CHECK_VASTATUS(va_status, "vaCreateContext"); + + va_status = vaCreateBuffer(va_dpy_1, context_id_1, + VAPictureParameterBufferType, + sizeof(VAPictureParameterBufferMPEG2), + 1, &pic_param, + &pic_param_buf); + CHECK_VASTATUS(va_status, "vaCreateBuffer"); + + va_status = vaCreateBuffer(va_dpy_1, context_id_1, + VAIQMatrixBufferType, + sizeof(VAIQMatrixBufferMPEG2), + 1, &iq_matrix, + &iqmatrix_buf); + CHECK_VASTATUS(va_status, "vaCreateBuffer"); + + va_status = vaCreateBuffer(va_dpy_1, context_id_1, + VASliceParameterBufferType, + sizeof(VASliceParameterBufferMPEG2), + 1, + &slice_param, &slice_param_buf); + CHECK_VASTATUS(va_status, "vaCreateBuffer"); + + va_status = vaCreateBuffer(va_dpy_1, context_id_1, + VASliceDataBufferType, + 0xc4 - 0x2f + 1, + 1, + mpeg2_clip + 0x2f, + &slice_data_buf); + CHECK_VASTATUS(va_status, "vaCreateBuffer"); + + va_status = vaBeginPicture(va_dpy_1, context_id_1, surface_id_1); + CHECK_VASTATUS(va_status, "vaBeginPicture"); + + va_status = vaRenderPicture(va_dpy_1, context_id_1, &pic_param_buf, 1); + CHECK_VASTATUS(va_status, "vaRenderPicture"); + + va_status = vaRenderPicture(va_dpy_1, context_id_1, &iqmatrix_buf, 1); + CHECK_VASTATUS(va_status, "vaRenderPicture"); + + va_status = vaRenderPicture(va_dpy_1, context_id_1, &slice_param_buf, 1); + CHECK_VASTATUS(va_status, "vaRenderPicture"); + + va_status = vaRenderPicture(va_dpy_1, context_id_1, &slice_data_buf, 1); + CHECK_VASTATUS(va_status, "vaRenderPicture"); + + va_status = vaEndPicture(va_dpy_1, context_id_1); + CHECK_VASTATUS(va_status, "vaEndPicture"); + + va_status = vaSyncSurface(va_dpy_1, surface_id_1); + CHECK_VASTATUS(va_status, "vaSyncSurface"); + + //vaExportSurface to get surface prime_fd + VADRMPRIMESurfaceDescriptor desc; + memset(&desc, 0, sizeof(VADRMPRIMESurfaceDescriptor)); + va_status = vaExportSurfaceHandle(va_dpy_1, surface_id_1, VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2, 0, &desc); +////////////////////////////end decoding///////////////////////////////////////////////////////////// + +////////////////////////////copy out surface from va_dpy_1 to another surface in va_dpy_2//////////// + ////import surface from va_dpy_1 and create output surface + VASurfaceAttrib surf_attrib[2]; + + surf_attrib[0].type = VASurfaceAttribMemoryType; + surf_attrib[0].value.type = VAGenericValueTypeInteger; + surf_attrib[0].flags = VA_SURFACE_ATTRIB_SETTABLE; + surf_attrib[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2; + + surf_attrib[1].type = VASurfaceAttribExternalBufferDescriptor; + surf_attrib[0].value.type = VAGenericValueTypePointer; + surf_attrib[1].flags = VA_SURFACE_ATTRIB_SETTABLE; + surf_attrib[1].value.value.p = &desc; + va_status = vaCreateSurfaces( + va_dpy_2, + VA_RT_FORMAT_YUV420, CLIP_WIDTH, CLIP_HEIGHT, + &surface_id_2, 1, + surf_attrib, 2 + ); + CHECK_VASTATUS(va_status, "vaCreateSurfaces"); + + VASurfaceID surface_id_3; + va_status = vaCreateSurfaces( + va_dpy_2, + VA_RT_FORMAT_YUV420, CLIP_WIDTH, CLIP_HEIGHT, + &surface_id_3, 1, + NULL, 0 + ); + CHECK_VASTATUS(va_status, "vaCreateSurfaces"); + + //vaCopy + VACopyObject dst; + dst.obj_type = VACopyObjectSurface; + dst.object.surface_id = surface_id_3; + VACopyObject src; + src.obj_type = VACopyObjectSurface; + src.object.surface_id = surface_id_2; + VACopyOption option; + option.bits.va_copy_sync = VA_EXEC_SYNC; + option.bits.va_copy_mode = VA_EXEC_MODE_DEFAULT; + va_status = vaCopy(va_dpy_2, &dst, &src, option); + CHECK_VASTATUS(va_status, "vaCopy"); + + va_status = vaSyncSurface(va_dpy_2, surface_id_2); + va_status = vaSyncSurface(va_dpy_2, surface_id_3); + CHECK_VASTATUS(va_status, "vaSyncSurface"); +////////////////////////////end copy////////////////////////////////////////////////////////////////// + + vaDestroySurfaces(va_dpy_1, &surface_id_1, 1); + vaDestroySurfaces(va_dpy_2, &surface_id_2, 1); + vaDestroySurfaces(va_dpy_2, &surface_id_3, 1); + vaDestroyConfig(va_dpy_1, config_id); + vaDestroyContext(va_dpy_1, context_id_1); + + vaTerminate(va_dpy_1); + vaTerminate(va_dpy_2); + va_close_display(va_dpy_1); + va_close_display(va_dpy_2); + return 0; +}