Skip to content

Commit

Permalink
[Decode] Test shared surface copy between two media instances
Browse files Browse the repository at this point in the history
Signed-off-by: Xu, Zhengguo <[email protected]>
  • Loading branch information
Jexu committed Jun 17, 2024
1 parent 29c0a92 commit 5719b37
Show file tree
Hide file tree
Showing 3 changed files with 356 additions and 1 deletion.
6 changes: 5 additions & 1 deletion decode/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand All @@ -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

Expand Down
3 changes: 3 additions & 0 deletions decode/meson.build
Original file line number Diff line number Diff line change
@@ -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)
348 changes: 348 additions & 0 deletions decode/mpeg2sharedsurfacecopy.cpp
Original file line number Diff line number Diff line change
@@ -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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <va/va.h>
#include <vector>
#include <va/va_drm.h>
#include "va_display.h"
#include <time.h>
#include <va/va_drmcommon.h>

#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;
}

0 comments on commit 5719b37

Please sign in to comment.